React Native - Animated.spring() isn't called as it should - react-native

The output I want :
When I click on the card, it is flipped and it set isValidated to true. When I click a second time, is it flipped back to its original position.
I don't understand why I need to trigger onPressCard two times in order for the card to flip.
Console output are real strange too :
'rotationValue 0', when pressed 1 time
'rotationValue3 0 rotationValue 0' when pressed a second time
Here is the code :
interface RotativeCardProps {
card: RotativeCardType,
index: number
}
const Rotative = ({ card, index }: RotativeCardProps) => {
const [isValidated, setIsValidated] = useState<boolean>(false);
let rotationValue = 0;
const animatedValue = new Animated.Value(0);
animatedValue.addListener(({ value }) => { rotationValue = value; });
const onPressCard = () => {
if (!isValidated) { setIsValidated(true); }
flipCard();
};
const flipCard = () => {
console.log('rotationValue', rotationValue);
if (rotationValue > 89) {
console.log('rotationValue2', rotationValue);
Animated.spring(animatedValue, {
toValue: 0,
friction: 8,
tension: 10,
useNativeDriver: true,
}).start();
} else {
console.log('rotationValue3', rotationValue);
Animated.spring(animatedValue, {
toValue: 180,
friction: 8,
tension: 10,
useNativeDriver: true,
}).start();
}
};
const frontInterpolate = animatedValue.interpolate({ inputRange: [0, 180], outputRange: ['0deg', '180deg'] });
const backInterpolate = animatedValue.interpolate({ inputRange: [0, 180], outputRange: ['180deg', '360deg'] });
const frontAnimatedStyle = { transform: [{ rotateY: frontInterpolate }] };
const backAnimatedStyle = { transform: [{ rotateY: backInterpolate }] };
```

flipCard();
calling this function onPressCard should be removed and moved to useEffect
useEffect(()=>{
flipCard();
},[isValidated])
this fill fix the issue as set state is blocking the animation

Related

React Native Animated If function

const OFFSET = useRef(new Animated.Value(0)).current;
const LOGO_ANIM_INTERPOLATE = OFFSET.interpolate({
inputRange: [-100,0],
outputRange: [ WINDOW_WIDTH/2-35,0],
extrapolate: 'clamp',
})
if (LOGO_ANIM_INTERPOLATE === WINDOW_WIDTH/2-35) {
alert('OK');
} else {
}
-----------
OnScroll in ScrollView
onScroll={
Animated.event(
[{nativeEvent: {
contentOffset: {
y: OFFSET,
},
},
}],
{ useNativeDriver: false },
)}
--------
An object move to the right accordingly Scroll y-offset.
If object get x-position = WINDOW_WIDTH/2-35 I want alert('OK');
IF function not working! Why?

React Native remove default State

When onPress then Element the code get the start position of the Element (Y_POSITION) and move/animated from the Y_POSITION to 200 (POSITION_INTERPOLATE). The code working good but there is one detail that needs to be changed in order to be perfected.
The detail is that onPress first move superfast from 0 (or any var is default in state useState(0) ) and after move to Y_POSITION and next to 200.
I try to change useState(0) with useState(null or false or true) but nothing change.
Do you have any idea what to do?
I give the basic code for my question.
const [Y_POSITION, setY_POSITION] = useState(0);
const POSITION_ANIM = useRef(new Animated.Value(0)).current
const POSITION_INTERPOLATE = POSITION_ANIM.interpolate({
inputRange: [0, 1],
outputRange: [Y_POSITION, 200],
})
const onPress = () => {
newRef?.current?.measure( (fx, fy, width, height, px, py) => {
setY_POSITION(fy)
Animated.timing(
POSITION_ANIM,
{
toValue: 1,
duration: 500,
useNativeDriver: false
}
).start();
})
}
And an element with transform: [{ translateY: POSITION_INTERPOLATE }],

React Native - Unfold collapsed header when user moves this

I have a header that is collapsed when scrolling in a flatlist, I achieved this with the following code
const positionY = React.useRef(new Animated.Value(0)).current;
const onScroll = Animated.event(
[{ nativeEvent: { contentOffset: { y: positionY } } }],
{
useNativeDriver: true,
}
);
const translateY = positionY.interpolate({
inputRange: [0, headerHeight],
outputRange: [0, -(headerHeight - 64)],
extrapolate: 'clamp',
});
snack whit complete code https://snack.expo.io/#gustperz/collapsible-header
I would like to be able to unfold the header on demand when the user pull down on the sticky header, without scrolling over the list.
I did Double animation
By scrolling + drawer behavior
const beyondLength = 100000
const onScroll = Animated.event(
[{ nativeEvent: { contentOffset: { y: positionY.current } } }],
{ useNativeDriver: true },
);
const translateY = positionY.current.interpolate({
inputRange: [0, headerHeight + 100, beyondLength, beyondLength+1, beyondLength+150],
outputRange: [
0,
-(headerHeight - 64),
-(headerHeight - 64),
-(headerHeight - 65),
0,
],
extrapolate: 'clamp',
});
const panResponder = React.useMemo(
() =>
PanResponder.create({
onMoveShouldSetPanResponder: () => true,
onPanResponderMove: (event, gestureState) => {
positionY.current.setValue(gestureState.dy + beyondLength);
},
}),
[],
);
expo

How corretly debounce react native animation

I'm building an translateY e opacity component to animate my submit button that appears at the end of the form. The problem is that everytime the prop changes too fast the button stops working
[...]
class ShyButton extends PureComponent {
constructor(props) {
super(props)
this.state = { height: 0, visible: props.isVisible }
this.animatedValue = new Animated.Value(props.isVisible ? 1 : 0)
}
componentDidUpdate(prevProps, prevState) {
const { isVisible } = this.props
if (prevProps.isVisible !== isVisible) {
if (isVisible) { this.toggleVisibility(prevState, true) }
Animated.timing(this.animatedValue,
{ toValue: isVisible ? 1 : 0, duration: 800, useNativeDriver: true }
).start(() => { if (!isVisible) { this.toggleVisibility(prevState, false) } })
}
}
toggleVisibility = (prevState, visible) => this.setState({ ...prevState, visible })
onLayout = event => this.setState({ height: event.nativeEvent.layout.height })
render() {
const { isVisible, style, children, ...props } = this.props
const { height, visible } = this.state
const animatedStyle = {
opacity: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
}),
transform: [
{
translateY: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [height, 0],
extrapolate: 'clamp'
})
}
]
}
const combinedStyle = StyleSheet.flatten([style, { opacity: 0, transform: [{ translateY: 0 }] }])
const animatingStyle = StyleSheet.flatten([combinedStyle, animatedStyle])
return (
<Animated.View onLayout={this.onLayout} style={visible ? animatingStyle : combinedStyle} {...props}>
{visible ? children : null}
</Animated.View>
)
}
}
[...]
The biggest problem is when auto-correct is used on the first word the text length goes to zero (test used to show or hide it) and back too fast, blocking the animation
Imgur

Transition Animation for react native(react-navigation and redux)

I followed the below code to implement Screen transition animation but it doesn't seem to be working. I am using react-navigation(1.0.0-beta.26) with redux.
const transitionConfig = () => {
return {
transitionSpec: {
duration: 750,
easing: Easing.out(Easing.poly(4)),
timing: Animated.timing,
useNativeDriver: true,
},
screenInterpolator: sceneProps => {
const { position, layout, scene, index, scenes } = sceneProps
const toIndex = index
const thisSceneIndex = scene.index
const height = layout.initHeight
const width = layout.initWidth
const translateX = position.interpolate({
inputRange: [thisSceneIndex - 1, thisSceneIndex, thisSceneIndex + 1],
outputRange: [width, 0, 0]
})
const translateY = position.interpolate({
inputRange: [0, thisSceneIndex],
outputRange: [height, 0]
})
const slideFromRight = { transform: [{ translateX }] }
const slideFromBottom = { transform: [{ translateY }] }
const lastSceneIndex = scenes[scenes.length - 1].index
if (lastSceneIndex - toIndex > 1) {
if (scene.index === toIndex) return
if (scene.index !== lastSceneIndex) return { opacity: 0 }
return slideFromBottom
}
return slideFromRight
},
}}
export const AppNavigator = StackNavigator({
Screen1: {screen: Screen1, navigationOptions:{header:null}},
Screen2: {screen: Screen2, navigationOptions:{header:null}},
}, {
initialRouteName: 'Screen1',
transitionConfig,
});
class App extends Component {
return (
<View>
<AppNavigator />
</View>
)
}
I am navigating using the redux dispatch as mentioned below
this.props.navigation.dispatch({ type: 'Screen2' })