how to use navigation.navigate together with render() to change tab - react-native

I have a Floating Action Button with two internal buttons, the idea is that after clicking on the first FAB (Floating Action Button) the others are displayed, what I require is that I can click on one of the buttons that was displayed and send me to the login or to another tab, page, route.
The error I have is that I don't know where I can do the "const navigation = useNavigation()" to use the navigator and send the user to another tab
i tried to use this.props, but i couldn't get it
export default class FloatingButton extends React.Component {
handleSignOut = () => {
Alert.alert("Position 1")
authentication
.signOut()
.then(() => {
this.props.navigation.navigate("Login")
})
.catch(error => alert(error.message))
}
handleSignOut2 = () =>{Alert.alert("Position 2")}
animation = new Animated.Value(0);
toggleMenu = () => {
const toValue = this.open ? 0 : 1;
Animated.spring(this.animation, {
toValue,
friction: 5,
useNativeDriver: false
}).start();
this.open = !this.open;
};
render() {
const pinStyle2 = {
transform: [
{ scale: this.animation },
{
translateY: this.animation.interpolate({
inputRange: [0, 1],
outputRange: [0, -10]
})
}
]
};
const pinStyle = {
transform: [
{ scale: this.animation },
{
translateY: this.animation.interpolate({
inputRange: [0, 1],
outputRange: [0, -20]
})
}
]
};
const rotation = {
transform: [
{
rotate: this.animation.interpolate({
inputRange: [0, 1],
outputRange: ["0deg", "45deg"]
})
}
]
};
const opacity = this.animation.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [0, 0, 1]
})
return (
<View style={[styles.container, this.props.style]}>
<TouchableWithoutFeedback onPress={this.handleSignOut}>
<Animated.View style={[styles.button, styles.secondary, styles.menu, pinStyle, opacity]}>
<Entypo name="add-to-list" size={24} color="white" />
</Animated.View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={this.handleSignOut2}>
<Animated.View style={[styles.button, styles.secondary, styles.menu, pinStyle2, opacity]}>
<Entypo name="check" size={24} color="white" />
</Animated.View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={this.toggleMenu}>
<Animated.View style={[styles.button, styles.menu, rotation]}>
<AntDesign name="plus" size={24} color="white" />
</Animated.View>
</TouchableWithoutFeedback>
</View>
);
}

According to the react documentation "You can’t use Hooks inside a class component". (https://reactjs.org/docs/hooks-faq.html). And thats what you're doing useNavigation is a hook and you're calling it inside a class. So either
- Change your class into a function
or
- Find a way to express the same functionality as the useNavigation hook but in a class

Related

Custom Drawer animation won't work after updating drawer navigation 6

i need some help about my custom drawer .
it used to work perfectly with slide animation but after updating to drawer v6.
the package react-native-reanimated has been updated too.
he stops work. can you help me guys. thanks
const CustomDrawer = ({navigation}) => {
const [progress, setProgress] = React.useState(new Animated.Value(0));
const scale = Animated.interpolateNode(progress, {
inputRange: [0, 1],
outputRange: [1, 0.8],
});
const borderRadius = Animated.interpolateNode(progress, {
inputRange: [0, 1],
outputRange: [0, 26],
});
const animatedStyle = {borderRadius, transform: [{scale}]};
return (
<View style={{flex: 1, backgroundColor: COLORS.primary}}>
<Drawer.Navigator
screenOptions={{
headerShown: false,
sceneContainerStyle: {backgroundColor: 'transparent'},
drawerType: 'slide',
drawerStyle: {
flex: 1,
width: '65%',
paddingRight: 20,
backgroundColor: 'transparent',
},
}}
drawerContent={props => {
// setTimeout(() => {
setProgress(props.progress);
// }, 0);
return <CustomContentDrawer navigation={props.navigation} />;
}}>
<Drawer.Screen name="MainLayout">
{props => (
<MainLayout
{...props}
drawerAnimationStyle={animatedStyle}
navigation={navigation}
/>
)}
</Drawer.Screen>
</Drawer.Navigator>
</View>
);
};
const MainLayout = ({drawerAnimationStyle, navigation}) => {
return (
<Animated.View
style={{flex: 1, backgroundColor: 'white', ...drawerAnimationStyle}}>
<Text>MainLayout</Text>
</Animated.View>
);
};
With the latest update progress prop of drawerContent seems to return undefined. So the animation is not working.
Instead of using useState , we can use useDrawerProgress() hook in the Main component instead of Drawer component. All the animation logic needs to be implemented in Main Component.
//Main Component
const MainLayout = (props) => {
const progress = useDrawerProgress();
const scale = Animated.interpolateNode(progress, {
inputRange: [0, 1],
outputRange: [1, 0.8],
});
const borderRadius = Animated.interpolateNode(progress, {
inputRange: [0, 1],
outputRange: [0, 26],
});
const animatedStyle = {
borderRadius,
transform: [{ scale }],
};
return (
<Animated.View
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
backgroundColor: "white",
...animatedStyle,
}}
>
<Text>MainLayout</Text>
</Animated.View>
);
};
export default MainLayout;
PS: remove any animation logic and props passed in drawer component. We don't need them anymore.
useDrawerProgress - working
try this code:
const drawerProgress = useDrawerProgress();
const animatedStyle = useAnimatedStyle(() => {
const scale = interpolate(drawerProgress.value, [0, 1], [1, 0.8], {
extrapolateRight: Extrapolate.CLAMP,
});
const borderRadius = interpolate(drawerProgress.value, [0, 1], [0, 10], {
extrapolateRight: Extrapolate.CLAMP,
});
return {
transform: [{scale}],
borderRadius,
};
});
But write this code inside screens not in the DrawerContent, for me its working!!

How to make reusable component for tabbar in react native

I have a custom tabbar component and I want to add a button with animation and I want to make reusable but I can't figured out. For example I want to use it for 1,2,3... etc icons. I don't want to decide it in the component itself.The code is like below.
export const TabAddButton = () => {
const windowWidth = useWindowDimensions().width;
const buttonSize = useRef(new Animated.Value(1)).current;
const mode = useRef(new Animated.Value(0)).current;
const handlePress = () => {
Animated.sequence([
Animated.timing(buttonSize, {
toValue: 0.95,
duration: 5,
useNativeDriver: true,
}),
Animated.timing(mode, {
toValue: mode["_value"] === 0 ? 1 : 0,
duration: 150,
useNativeDriver: false,
}),
]).start();
};
const lockX = mode.interpolate({
inputRange: [0, 1],
outputRange: [windowWidth / 2 - 22, windowWidth / 2 - 22 - 60],
});
const lockY = mode.interpolate({
inputRange: [0, 1],
outputRange: [-20, -75],
});
const noteX = mode.interpolate({
inputRange: [0, 1],
outputRange: [windowWidth / 2 - 22, windowWidth / 2 - 22 + 60],
});
return (
<Box {...StyleSheet.absoluteFillObject} alignItems="center">
<Animated.View
style={[styles.secondaryView,{ left: lockX,top: lockY,}]}>
<TouchableOpacity style={styles.secondaryButton}>
<Feather name="lock" size={24} color="#FFF" />
</TouchableOpacity>
</Animated.View>
<Animated.View style={[styles.secondaryView,{ left: lockX,top: noteY,}]}>
<TouchableOpacity style={styles.secondaryButton}>
<Foundation name="clipboard-notes" size={24} color="#FFF" />
</TouchableOpacity>
</Animated.View>
<View style={[styles.button]}>
<Animated.View style={[transform: [{ scale: buttonSize }]]}>
<TouchableOpacity activeOpacity={1} onPress={handlePress} style={styles.primaryButton}
>
<Animated.View>
<FontAwesome5 name="plus" size={24} color="#FFF" />
</Animated.View>
</TouchableOpacity>
</Animated.View>
</View>
</Box>
);
};
I'd suggest something like this
childButtons = [
{
isPrimary: false,
iconName: 'lock',
iconType: 'Feather',
onPress: () => {},
},
{
isPrimary: false,
iconName: 'clipboard-notes',
iconType: 'Foundation',
onPress: () => {},
},
/** ... */
];
const AppTabSecondaryButton = ({ containerStyle, onPress, IconType, iconName }) => (
<Animated.View style={[styles.secondaryView, containerStyle]}>
<TouchableOpacity onPress={onPress} style={styles.secondaryButton}>
<IconType name={iconName} size={24} color="#FFF" />
</TouchableOpacity>
</Animated.View>
);
const AppTabPrimaryButton = ({ containerStyle, onPress, IconType, iconName }) => {
<View style={[styles.button]}>
<Animated.View style={containerStyle}>
<TouchableOpacity activeOpacity={1} onPress={onPress} style={styles.primaryButton}
>
<Animated.View>
<IconType name={iconName} size={24} color="#FFF" />
</Animated.View>
</TouchableOpacity>
</Animated.View>
</View>
};
export const TabAddButton = ({ childButtons }) => {
/** Other stuff */
const lockX = mode.interpolate({
inputRange: [0, 1],
outputRange: [windowWidth / 2 - 22, windowWidth / 2 - 22 - 60],
});
const lockY = mode.interpolate({
inputRange: [0, 1],
outputRange: [-20, -75],
});
const noteX = mode.interpolate({
inputRange: [0, 1],
outputRange: [windowWidth / 2 - 22, windowWidth / 2 - 22 + 60],
});
const btnContainerStyles = [
[styles.secondaryView, { left: lockX, top: lockY, }],
[styles.secondaryView, { left: lockX, top: noteY }],
/** ... */
];
return (
<Box {...StyleSheet.absoluteFillObject} alignItems="center">
{childButtons.map(({ iconName, iconType, onPress, isPrimary }, index) => (
isPrimary ? (<AppTabPrimaryButton /** supply props */ />) :
(<AppTabSecondaryButton /** supply props */ />)
))}
</Box>
);
};

Close Swipeable functional component

I have a Flatlist rendered with the following ListItemSwipeable and they hold as renderRightActions the RightActionsButton function. Swiping works and the button appears. However, I can not achieve that the button disappears when another element is swiped or the button is pressed.
const RightActionsButton = ({ progress, dragX, onPress }) => {
const scale = dragX.interpolate({
inputRange: [-100, 0],
outputRange: [1, 0],
extrapolate: "clamp"
});
return (
<TouchableOpacity onPress={onPress}>
<View>
<Animated.Text style={{ transform: [{ scale }] }}>
Button!
</Animated.Text>
</View>
</TouchableOpacity>
);
};
const ListItemSwipeable = ({data, onAction}) => {
return (
<Swipeable
renderRightActions={(progress, dragX) => (
<RightActionsButton progress={progress} dragX={dragX} onPress={onAction} />
)}
>
<View>
<Text>{data}</Text>
</View>
</Swipeable>
)
}
};
There are some hints here, however it is class based and I would need it for function based component.

react-native-animation : update state when animation color has changed

I want to update the state when animation color has changed.
When the animation changes from white to red, I want to update the state and display the updated state in the text label.
This is my code:
export default class AnimationHeader extends React.Component {
constructor(props) {
super(props)
this.state = {
scrollY:new Animated.Value(0),
headerColor:'white'
}
}
render() {
const HeaderHeight = this.state.scrollY.interpolate({
inputRange: [0, 200],
outputRange: [120, 120],
extrapolate: 'clamp'
})
const AnimateHeaderBackgroundColor = this.state.scrollY.interpolate({
inputRange: [ 70, 70 ],
outputRange: [ 'transparent', 'red'],
extrapolate: 'clamp'
})
return (
<View
style={styles.container}>
<Animated.View style={{width:'100%', height:HeaderHeight, backgroundColor:AnimateHeaderBackgroundColor, alignItems:'center', justifyContent:'center'}}>
<Text style={{ fontSize:30}}>Animated Header</Text>
</Animated.View>
<ScrollView
scrollEventThrottle={16}
onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }])}
style={{width:'100%', backgroundColor:'gray'}}>
<View style={{width:'100%', height:1000, backgroundColor:'blue', justifyContent:'center',alignItems:'center'}}>
<Text style={{color:'white', fontSize:30}}>headerColor:</Text>
//////////////////I want to display the updated state here
<Text style={{color:'white', fontSize:30}}>white</Text>
</View>
</ScrollView>
</View>
);
}
}
You can listen to the value of the animation
const animatedListener = this.state.animatedValue.addListener((progress) => {
this.setState({ progress: progress.value });
console.log(progress.value)
});
Just remember to remove the listener when done
componentWillUnmount() {
this.state.animatedValue.removeListener(animatedListener);
//or use for many listeners
this.state.animatedValue.removeAllListeners()
}
It is important to note that if you use userNativeDriver you will not be able to listen and always receive the initial value
I figured it out. According to react-native document react native animation
I could use Animated.Value.addListener to check my animation state.
I could simply add:
componentDidMount() {
this.state.scrollY.addListener(({value}) => {
if(value > 70){
this.setState({headerColor:'red'})
console.log('red')
}
if(value<70){
this.setState({headerColor:'white'})
console.log('white')
}
this._value = value, console.log(value,'value')});
}
Then, in my text label I just display the state:
this.state.headerColor

How do you Flip the screen like a coin transition in react native?

I am trying to make the screen flip like a coin when button pressed on it. What I have done up-till now is I have successfully flipped two small screens, but it comes to a bit large screen the code is not working. Like here in my code two simple buttons are working fine, but when I call view from other big screen, the view doesn't show up. I think it is because the view that will is flipped becomes invisible but remains on its place and other view can't be placed on that space, so when it comes to larger screen the whole thing doesn't show up. I am new to RN. Help.
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
Animated
} from 'react-native';
var screenWidth = require('Dimensions').get('window').width;
export default class animatedbasic extends Component {
componentWillMount() {
this.animatedValue = new Animated.Value(0);
this.value = 0;
this.animatedValue.addListener(({ value }) => {
this.value = value;
})
this.frontInterpolate = this.animatedValue.interpolate({
inputRange: [0, 180],
outputRange: ['0deg', '180deg'],
})
this.backInterpolate = this.animatedValue.interpolate({
inputRange: [0, 180],
outputRange: ['180deg', '360deg']
})
this.frontOpacity = this.animatedValue.interpolate({
inputRange: [89, 90],
outputRange: [1, 0]
})
this.backOpacity = this.animatedValue.interpolate({
inputRange: [89, 90],
outputRange: [0, 1]
})
}
flipCard() {
if (this.value >= 90) {
Animated.spring(this.animatedValue,{
toValue: 0,
friction: 8,
tension: 10
}).start();
} else {
Animated.spring(this.animatedValue,{
toValue: 180,
friction: 8,
tension: 10
}).start();
}
}
render() {
const frontAnimatedStyle = {
transform: [
{ rotateY: this.frontInterpolate }
]
}
const backAnimatedStyle = {
transform: [
{ rotateY: this.backInterpolate }
]
}
return (
<View style={{ flex:1, justifyContent:'center', alignItems:'center'}} >
<View >
<Animated.View style={[styles.flipCard, frontAnimatedStyle, {opacity: this.frontOpacity}]}>
</Animated.View>
<Animated.View style={[styles.flipCard, styles.flipCardBack, backAnimatedStyle, {opacity: this.backOpacity}]}>
<View>
<TouchableOpacity onPress={() => this.flipCard()} style={{ width:(screenWidth/2), height:70, backgroundColor:'black'}}>
<Text style={{color:'white', fontSize:22, fontWeight:'bold'}}> I am on Back</Text>
</TouchableOpacity>
</View>
</Animated.View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
flipCard: {
backfaceVisibility: 'hidden',
},
flipCardBack: {
top: 0,
},
});
I have also tried react-native-card-flip
Flipping.js
render() {
return (
<CardFlip style={styles.cardContainer} ref={(card) => this.card
=card}>
<FronEnd />
<Backend />
</CardFlip> }
FronEnd.js
render()
{
return (
<View>
<CardFlip style={styles.cardContainer} ref={(card) => this.card = card} >
....................................................
<TouchableOpacity onPress={() => this.card.flip()}
</TouchableOpacity >
</CardFlip>
</View>
);
}
}
Backend.js
render()
{
return (
<View>
<CardFlip style={styles.cardContainer} ref={(card) => this.card = card} >
.......................
<TouchableOpacity onPress={() => this.card.flip()}
</TouchableOpacity >
</CardFlip>
</View>
);
}
You can use a npm module for this :
Installation :
npm install --save react-native-card-flip
Usage :
import CardFlip from 'react-native-card-flip';
<CardFlip style={styles.cardContainer} ref={(card) => this.card = card} >
<TouchableOpacity style={styles.card} onPress={() => this.card.flip()} ><Text>AB</Text></TouchableOpacity>
<TouchableOpacity style={styles.card} onPress={() => this.card.flip()} ><Text>CD</Text></TouchableOpacity>
</CardFlip>
See Output
Npm module : Github