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)
Related
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
componentWillReceiveProps(nextProps) {
if (this.props.active !== nextProps.active) {
Animated.timing(this._active, {
duration: 300,
easing: Easing.bounce,
toValue: Number(nextProps.active),
}).start();
}
}
This is the code of react-native-sortable-list.
And what I am trying to do is change this code with react-hook
Is there any help can I get to change componentWillReceiveProps part to functional component?
You can use useEffect with dependency list. when props.active changes component will rerender
useEffect(()=>{
Animated.timing(props.active, {
duration: 300,
easing: Easing.bounce,
toValue: Number(props.active),
}).start();
},[props.active])
I am using React Native to render a Chart.
I have 3 custom tabs in my app, when sliding between them I am getting new data and apply translation animation to highlight the selected tab.
I am facing a 1 second latency when scrolling. I investigated the latency and there is one parameter in setState() that is causing it, which is a big array of data.
I am already using async / await.
I tried to put setState() inside a setTimeout but the final result isn't smooth.
Is there a way to optimize setting big array in the state ? Or play the animation inpendently from setState() ?
Update
await Animated.spring(translateBottomX, {
toValue: type,
duration: 100,
}).start();
if (segment === 1) {
await Animated.parallel([
Animated.spring(translateXBottomTabOne, {
toValue: 0,
duration: 100,
}).start(),
Animated.spring(translateXBottomTabTwo, {
toValue: width,
duration: 100,
}).start(),
]);
} else if (segment === 2) {
await Animated.parallel([
Animated.spring(translateXBottomTabOne, {
toValue: width,
duration: 100,
}).start(),
Animated.spring(translateXBottomTabTwo, {
toValue: 0,
duration: 100,
}).start(),
]);
} else if (segment === 3) {
await Animated.parallel([
Animated.spring(translateXBottomTabOne, {
toValue: width,
duration: 0,
}).start(),
Animated.spring(translateXBottomTabTwo, {
toValue: width,
duration: 100,
}).start(),
]);
}
setTimeout(() => {
this.setState({
dataAxeX
});
}, 500);
// using it here
<XAxis
data={dataAxeX}
formatLabel={(_, index) => dataAxeX[index].Datetime}
contentInset={styles.xAxisContentInset}
svg={{
fill: "#B6C1DF",
...styles.xAxisStyle,
}}
/>
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?
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()