React native shaking pin view when pin incorrect - react-native

i am trying to implement a feature when user enters the wrong password the 4 small circles shake to the right and left.
I created an animation component to test my code and it was working but now my problem is how do i apply it only when the password is incorrect?
Currently when i enter an incorrect password nothing happens. What i expect is for the view to move horizontally.
const shake = new Animated.Value(0.5);
const [subtle,setSubtle]=useState(true);
const [auto,setAuto]=useState(false);
const translateXAnim = shake.interpolate({
inputRange: [0, 1],
outputRange: [subtle ? -8 : -16, subtle ? 8 : 16],
});
const getAnimationStyles = () => ({
transform: [
{
translateX: translateXAnim,
},
],
});
const runAnimation = () => {
Animated.sequence([
Animated.timing(shake, {
delay: 300,
toValue: 1,
duration: subtle ? 300 : 200,
easing: Easing.out(Easing.sin),
useNativeDriver: true,
}),
Animated.timing(shake, {
toValue: 0,
duration: subtle ? 200 : 100,
easing: Easing.out(Easing.sin),
useNativeDriver: true,
}),
Animated.timing(shake, {
toValue: 1,
duration: subtle ? 200 : 100,
easing: Easing.out(Easing.sin),
useNativeDriver: true,
}),
Animated.timing(shake, {
toValue: 0,
duration: subtle ? 200 : 100,
easing: Easing.out(Easing.sin),
useNativeDriver: true,
}),
Animated.timing(shake, {
toValue: 0.5,
duration: subtle ? 300 : 200,
easing: Easing.out(Easing.sin),
useNativeDriver: true,
}),
]).start(() => {
if (auto) runAnimation();
});
};
const stopAnimation = () => {
shake.stopAnimation();
};
const handleConfirm = async()=>{
const result = await authApi();
if(!result.ok) {
setAuto(true)
setSubtle(true)
runAnimation()
stopAnimation()
return setLoginFailed(true);
}
setLoginFailed(false);
};
return(
<Animated.View style={[getAnimationStyles()]}>
<View style={styles.circleBlock}>
{
password.map(p=>{
let style =p != ''?styles.circleFill
: styles.circle
return <View style={style}></View>
})
}
</View>
</Animated.View>

issue is that you didn't use useRef() for
const shake = new Animated.Value(0.5);
should be
const shake = useRef(new Animated.Value(0.5)).current;
useRef returns a mutable ref object whose .current property is
initialized to the passed argument (initialValue). The returned object
will persist for the full lifetime of the component.
https://reactjs.org/docs/hooks-reference.html#useref
made separate expo snack with same input and output range values for animation shake effect. check it out.
Expo: https://snack.expo.io/#klakshman318/runshakeanimation

Related

React Native Animation Boomerang style

I am trying to create a red led "Recording Like" element. I'd like to see it blinking smoothly.
useEffect(() => {
Animated.loop(
Animated.timing(
fadeAnim,
{
toValue: 0,
duration: 1000
}
).start(() =>{
Animated.timing(
fadeAnim,
{
toValue: 1,
duration: 1000
}
).start();
})
).start();
}, [fadeAnim])
<Animated.View style={[styles.recordingLed, {opacity: fadeAnim}]} />
It actually goes to 0, then to 1 and then stop. I need something continuos, endless. Any clue ?
You need to add some Easing (https://reactnative.dev/docs/easing) to your animation run smoothly, example:
const fadeAnim = new Animated.Value(0);
useEffect(() => {
Animated.loop(
Animated.timing(fadeAnim, {
toValue: 1,
duration: 1000,
easing: Easing.bezier(0.645, 0.045, 0.355, 1.0),
useNativeDriver: true,
}),
).start();
}, [fadeAnim]);
<Animated.View style={[styles.recordingLed, {opacity: fadeAnim}]} />
Also you can check this:
Maybe some pre made animations from can help you https://github.com/oblador/react-native-animatable#animations-2 ? Remember to mark the looping flag (https://github.com/oblador/react-native-animatable#looping)

React native animation is no working with setState function

I have this function:
const moveSwitch = () => {
setLeftStatus(!leftStatus);
Animated.timing(xValue, {
toValue: leftStatus ? 0 : 26,
duration: 300,
easing: Easing.linear,
useNativeDriver: false,
}).start();
};
It works if I remove the conditional option and setState.
Any suggestions please?
If anyone comes around this problem here is how I solved it.
Since setState function re-renders component animation was not working.
So I just created ref using useRef and updated it like this:
const moveSwitch = () => {
Animated.timing(xValue, {
toValue: leftStatus.current ? 0 : 26,
duration: 300,
easing: Easing.linear,
useNativeDriver: false,
}).start(event => {
if (event.finished) {
if (leftStatus.current) {
return (leftStatus.current = false);
} else {
return (leftStatus.current = true);
}
}
});
};

multiple react native animations with reanimated base on a state?

I am new to react native animations and I am specifically using react native reanimated, this is my code old code which is used in text input, I am changing the fontsize and translate Y of a label:
const labelSize = new Animated.Value(14);
const translateY = new Animated.Value(0);
const onFocus = () => {
setHasFocused(true);
Animated.timing(labelSize, {
toValue: 11,
duration: 250,
easing: Easing.in(Easing.ease),
}).start();
Animated.timing(top, {
toValue: -14,
duration: 250,
easing: Easing.in(Easing.ease),
}).start();
};
const onBlur = () => {
setHasFocused(false);
Animated.timing(labelSize, {
toValue: 14,
duration: 250,
easing: Easing.out(Easing.ease),
}).start();
Animated.timing(top, {
toValue: 0,
duration: 250,
easing: Easing.in(Easing.ease),
}).start();
};
however it doesn't seem to feel right, I've researched and resulted to this, I believe I have to use clock and timing with this, which I find hard and can't make to work, what I want to do is something like this:
const clock = new Clock();
useCode(
() => [
set(isPlaying, hasFocused ? 1 : 0),
set(translateY, hasFocused ? 1 : 0),
],
[hasFocused]
);
now I believe with timing I have to use clock with it:
const state = {
finished: new Animated.Value(0),
position: new Animated.Value(0),
frameTime: new Animated.Value(0),
time: new Animated.Value(0),
};
const config = {
toValue: new Animated.Value(1),
duration: 3000,
easing: Easing.inOut(Easing.ease),
};
timing(clock, state, config)
what I simply want to do is update animation values based if the input is focused and not, help?

React Native spawn multiple Animated.View with a time delay

I have a Wave component that unmounts as soon as it goes out of bounds.
This is my result so far: https://streamable.com/hmjo6k
I would like to have multiple Waves spawn every 300ms, I've tried implementing this using setInterval inside useEffect, but nothing behaves like expected and app crashes
const Wave = ({ initialDiameter, onOutOfBounds }) => {
const scaleFactor = useRef(new Animated.Value(1)).current,
opacity = useRef(new Animated.Value(1)).current
useEffect(() => {
Animated.parallel(
[
Animated.timing(scaleFactor, {
toValue: 8,
duration: DURATION,
useNativeDriver: true
}),
Animated.timing(opacity, {
toValue: 0.3,
duration: DURATION,
useNativeDriver: true
})
]
).start(onOutOfBounds)
})
return (
<Animated.View
style={
{
opacity,
backgroundColor: 'white',
width: initialDiameter,
height: initialDiameter,
borderRadius: initialDiameter/2,
transform: [{scale: scaleFactor}]
}
}
/>
)
}
export default Wave
const INITIAL_WAVES_STATE = [
{ active: true },
]
const Waves = () => {
const [waves, setWaves] = useState(INITIAL_WAVES_STATE),
/* When out of bounds, a Wave will set itself to inactive
and a new one is registered in the state.
Instead, I'd like to spawn a new Wave every 500ms */
onWaveOutOfBounds = index => () => {
let newState = waves.slice()
newState[index].active = false
newState.push({ active: true })
setWaves(newState)
}
return (
<View style={style}>
{
waves.map(({ active }, index) => {
if (active) return (
<Wave
key={index}
initialDiameter={BUTTON_DIAMETER}
onOutOfBounds={onWaveOutOfBounds(index)}
/>
)
else return null
})
}
</View>
)
}
export default Waves
I think the useEffect cause the app crashed. Try to add dependencies for the useEffect
useEffect(() => {
Animated.parallel(
[
Animated.timing(scaleFactor, {
toValue: 8,
duration: DURATION,
useNativeDriver: true
}),
Animated.timing(opacity, {
toValue: 0.3,
duration: DURATION,
useNativeDriver: true
})
]
).start(onOutOfBounds)
}, [])

React native animation is not working for the second time

I have used the default "Animated" package with react native for my animations in the application. Animations in the following code is working fine. But when I navigate to another page and come back to this screen the animation is not working. Once the page gets loaded from ground level only it is working again. What could be the reason ? Can someone please help me to sort this out.
class LoginScreen extends Component {
static navigationOptions = {
header: null
}
state = {
username: '',
password: '',
animation: {
usernamePostionLeft: new Animated.Value(795),
passwordPositionLeft: new Animated.Value(905),
loginPositionTop: new Animated.Value(1402),
statusPositionTop: new Animated.Value(1542)
}
}
navigateToScreen = link => event => {
this.props.navigation.navigate(link)
}
componentDidMount() {
const timing = Animated.timing
Animated.parallel([
timing(this.state.animation.usernamePostionLeft, {
toValue: 0,
duration: 1700
}),
timing(this.state.animation.passwordPositionLeft, {
toValue: 0,
duration: 900
}),
timing(this.state.animation.loginPositionTop, {
toValue: 0,
duration: 700
}),
timing(this.state.animation.statusPositionTop, {
toValue: 0,
duration: 700
})
]).start()
}
render() {
return (
<View style={styles.container}>
<ImageBackground
source={lem_bg}
blurRadius={10}
style={styles.imageBgContainer}>
<View style={styles.internalContainer}>
<Animated.View style={{position: 'relative', top:
this.state.animation.usernamePostionLeft, width: '100%'}}>
<Text style={styles.LEMHeader}>LEM<Text style={styles.followingtext}>mobile</Text></Text>
</Animated.View>
</ImageBackground>
</View>
....MORE JSX ARE THERE...
)
}
}
componentDidMount() won't call when you navigate back from another screen. for this, you have to create your own callback method for performing this animation when you pop() from another screen. Consider below code change
first screen
navigateToScreen = link => event => {
this.props.navigation.navigate(link,{
callback:this.runAnimation
})
}
componentDidMount() {
this.runAnimation()
}
runAnimation(){
const timing = Animated.timing
Animated.parallel([
timing(this.state.animation.usernamePostionLeft, {
toValue: 0,
duration: 1700
}),
timing(this.state.animation.passwordPositionLeft, {
toValue: 0,
duration: 900
}),
timing(this.state.animation.loginPositionTop, {
toValue: 0,
duration: 700
}),
timing(this.state.animation.statusPositionTop, {
toValue: 0,
duration: 700
})
]).start()
}
on the second screen when you pop() navigation to back, call this callback
this.props.navigator.pop()
this.props.callback()