How to make an arrow icon move up and down - react-native

I want to make an Arrow Icon to move up and down with animation using react native expo. Please any help on how to go about it? this is what I've written so far.
constructor(props) {
super(props);
this.translation = React.createRef(new Animated.Value(0)).current;
}
componentDidMount(){
Animated.timing(this.translation,{
toValue: 50
}).start();
}
<Animated.View style={{ transform: [{translateY: this.translation}], position: 'absolute', bottom: 50, alignSelf: 'flex-end', paddingRight: 19}}>
<Entypo name="arrow-bold-down" style={bottomTab.arrow} />
</Animated.View>

Do you want to animate infinitely?
animate() {
Animated.timing(this.translation, {
toValue: 50,
duration: 500
}).start(() => {
Animated.timing(this.translation, {
toValue: 0,
duration: 500
}).start(() => {
this.animate()
})
})
}
componentDidMount(){
this.animate()
}

Related

Why all the Icons of my custom bottom tab bar navigator are moving at the same time?

I am trying to create a CustomBottomTabNavigator in react native. By now I have applied the linear gradient and added the icons on top of the tab. My goal is to move the icon upwards when the focus is on it, but for some reason, all the icons are moving upwards when the focus is on only one icon.
Here is the code:
import React, { useRef } from "react";
import {
View,
Text,
StyleSheet,
Animated,
TouchableOpacity,
} from "react-native";
import * as Icons from "#expo/vector-icons";
import { LinearGradient } from "expo-linear-gradient";
const CustomTabBar = ({ state, descriptors, navigation }) => {
let icons_name = ["home", "search", "tv", "user"];
const animatedValueHome = useRef(new Animated.Value(0)).current;
const translateY = animatedValueHome.interpolate({
inputRange: [50, 100, 150],
outputRange: [25, 50, 75],
});
const animationHome = (focus, name) => {
console.log("name", name);
navigation.navigate(name);
if (focus === true) {
Animated.timing(animatedValueHome, {
toValue: -25,
duration: 1000,
useNativeDriver: false,
}).start();
} else {
Animated.timing(animatedValueHome, {
toValue: 0,
duration: 1000,
useNativeDriver: false,
}).start();
}
};
return (
<LinearGradient
colors={["#181823", "#3A3A46", "#3A3A46"]}
start={{ x: 0, y: 0.5 }}
end={{ x: 1, y: 0.5 }}
locations={[0.2, 0.6, 0.3]}
style={styles.container}
>
<View style={styles.tabs}>
{state.routes.map((route, index) => {
const isFocused = state.index === index;
return (
<Animated.View
key={index}
style={{
flex: 1,
flexDirection: "row",
transform: [{ translateY }],
}}
>
<Icons.Feather
name={icons_name[`${index}`]}
size={24}
color="#fff"
onPress={() => animationHome(isFocused, route.name)}
/>
</Animated.View>
);
})}
</View>
</LinearGradient>
);
};
export default CustomTabBar;
const styles = StyleSheet.create({
container: {
position: "absolute",
height: 40,
bottom: 20,
right: 30,
left: 20,
elevation: 2,
borderRadius: 20,
},
tabs: {
flex: 1,
flexDirection: "row",
alignItems: "center",
marginLeft: 48,
},
});
Here is the gif of the animation that is happening
Gif. I am using animated API from react-native to achieve this animation.
Let each of the child components have their own animation values.
// In the parent component
{state.routes.map((route, index) => {
const isFocused = state.index === index;
return <Child isFocused={isFocused} />;
})}
// Then for each child
const Child = ({ isFocused }) => {
const animatedValueHome = useRef(new Animated.Value(0)).current;
const translateY = animatedValueHome.interpolate({
inputRange: [50, 100, 150],
outputRange: [25, 50, 75],
});
const animationHome = (focus, name) => {
console.log("name", name);
navigation.navigate(name);
if (focus === true) {
Animated.timing(animatedValueHome, {
toValue: -25,
duration: 1000,
useNativeDriver: false,
}).start();
} else {
Animated.timing(animatedValueHome, {
toValue: 0,
duration: 1000,
useNativeDriver: false,
}).start();
}
};
return (
<Animated.View
style={{
transform: [{ translateY }],
}}
>
<Icons.Feather onPress={() => animationHome(isFocused, route.name)}/>
</Animated.View>
);
}

react native animation is not working smootly

i am trying to create animated header where the height, fontSize and position are being changed while scrolling like header of uber
it works but it is not smooth
when i scroll slowly it shakes very fast
constructor:
constructor(props) {
super(props);
this.state = {
fontSizeAnimation: new Animated.Value(30),
positionX: new Animated.Value(0),
positionY: new Animated.Value(0),
height: new Animated.Value(0),
positionAnimation: new Animated.ValueXY(),
scrollY: 0,
counter: 0,
}
}
function of animation:
animateTitle = (e) => {
const scrollY = e.nativeEvent.contentOffset.y;
if(scrollY - this.state.scrollY > 5 || scrollY - this.state.scrollY < -5) {
this.setState({counter: this.state.counter+1})
this.setState({scrollY});
Animated.parallel([
Animated.timing(this.state.height, {
toValue: this.state.scrollY,
duration: 0,
easing: Easing.linear
}),
Animated.timing(this.state.fontSizeAnimation, {
toValue: this.state.scrollY,
duration: 0,
easing: Easing.linear
})
]).start(() => {
this.state.positionAnimation.setValue({
x: this.state.scrollY > 50? 50 : this.state.scrollY,
y: this.state.scrollY > 50? -50 : -this.state.scrollY,
})
})
}
}
render function:
render() {
const interpolatedFontSize = this.state.fontSizeAnimation.interpolate({
inputRange: [0, 50],
outputRange: [30, 20],
extrapolate: "clamp"
});
const interpolatedHeight = this.state.height.interpolate({
inputRange: [0, 50],
outputRange: [120, 60],
extrapolate: "clamp"
});
return (
<View>
<Animated.View style={[styles.header, {height: interpolatedHeight}]}>
<Image source={require("./images/back-button.png")} style={styles.back} />
<Animated.Text style={[styles.title, { fontSize: interpolatedFontSize, transform: this.state.positionAnimation.getTranslateTransform() }]}>Title</Animated.Text>
</Animated.View>
<ScrollView
onScroll={(e) => this.animateTitle(e)}
contentContainerStyle={{minHeight: "100%", height: 1000, backgroundColor: "grey"}}
>
<View style={{height: 800, backgroundColor: "red", width: "100%", marginBottom: 10}}>
</View>
</ScrollView>
</View>
)
}
}
style:
const styles = StyleSheet.create({
back: {
position: "absolute",
top: 20,
left: 10,
height: 30,
width: 30
},
title: {
position: "absolute",
paddingTop: 5,
top: 60,
left: 10
},
header: {
position: "relative",
backgroundColor:"grey",
}
});
Your animations are currently running on JS thread. You can easily move the animations to the native thread by:
Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
useNativeDriver: true, // <-- Adding this line
}).start();
Using native drivers can give you a performance boost as it clears the JS thread for other tasks. Try it!
You should use LayoutAnimation if you want to animate layouts smoothly (height in this case). Here's a link to get you started.

React Native animated input text

I want to show a cancel button, on the focus TextInput animation.
I did the following code, but a cancel button does not display and follow the box when focused. It's only shown after the animation end.
And when cancel button displayed, it is not on the same line with textinput.
How do I fix this?
const { width } = Dimensions.get('window');
const PADDING = 16;
const SEARCH_FULL_WIDTH = width - PADDING * 2; //search_width when unfocused
const SEARCH_SHRINK_WIDTH = width - PADDING - 90; //search_width when focused
class Search extends React.Component {
constructor(props: IProps) {
super(props);
this.state = {
inputLength: new Animated.Value(SEARCH_FULL_WIDTH),
searchBarFocused: false,
}
}
private onFocus = () => {
Animated.timing(this.state.inputLength, {
toValue: SEARCH_SHRINK_WIDTH,
duration: 250,
}).start(() => this.setState({ searchBarFocused: true }));
}
private onBlur = () => {
Animated.timing(this.state.inputLength, {
toValue: SEARCH_FULL_WIDTH,
duration: 250,
}).start(() => this.setState({ searchBarFocused: false }));
}
<View style={styles.searchContainer}>
<Animated.View style={[
styles.search,
{
width: this.state.inputLength,
position: 'absolute',
left: 16,
alignSelf: 'center'
},
searchBarFocused === true ? undefined : { justifyContent: 'center' }
]}>
<Image source={searchIcon} style={styles.image} />
<TextInput
style={styles.searchInput}
....
onBlur={this.onBlur}
onFocus={this.onFocus}
/>
</Animated.View>
{searchBarFocused &&
<Touchable style={styles.cancelSearch} onPress={this.cancelSearch}>
<Text style={styles.cancelSearchText}>Cancel</Text>
</Touchable>
}
</View>
const styles = StyleSheet.create({
searchContainer: {
flexDirection: 'row',
height: 72,
borderBottomColor: SOLITUDE_COLOR,
},
search: {
flex: 1,
flexDirection: 'row',
height: 40,
borderRadius: 6,
},
cancelSearch: {
marginHorizontal: 16,
textAlign: 'center',
justifyContent: 'center'
}
});
gif: when unfocus and focused
Here is a slightly modified version of your code.
import React from "react";
import {
Dimensions,
View,
Animated,
TextInput,
TouchableOpacity,
StyleSheet,
} from "react-native";
const { width } = Dimensions.get("window");
const PADDING = 16;
const SEARCH_FULL_WIDTH = width - PADDING * 2; //search_width when unfocused
const SEARCH_SHRINK_WIDTH = width - PADDING - 90; //search_width when focused
const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity);
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
inputLength: new Animated.Value(SEARCH_FULL_WIDTH),
cancelPosition: new Animated.Value(0),
opacity: new Animated.Value(0),
searchBarFocused: false
};
}
onFocus = () => {
Animated.parallel([
Animated.timing(this.state.inputLength, {
toValue: SEARCH_SHRINK_WIDTH,
duration: 250
}),
Animated.timing(this.state.cancelPosition, {
toValue: 16,
duration: 400
}),
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 250
})
]).start();
};
onBlur = () => {
Animated.parallel([
Animated.timing(this.state.inputLength, {
toValue: SEARCH_FULL_WIDTH,
duration: 250
}),
Animated.timing(this.state.cancelPosition, {
toValue: 0,
duration: 250
}),
Animated.timing(this.state.opacity, {
toValue: 0,
duration: 250
})
]).start();
};
render() {
const { searchBarFocused } = this.state;
return (
<View style={styles.searchContainer}>
<Animated.View
style={[
styles.search,
{
width: this.state.inputLength,
position: "absolute",
left: 16,
alignSelf: "center"
},
searchBarFocused === true ? undefined : { justifyContent: "center" }
]}
>
<TextInput
style={styles.searchInput}
onBlur={this.onBlur}
onFocus={this.onFocus}
placeholder="Type something"
/>
</Animated.View>
<AnimatedTouchable
style={[styles.cancelSearch, { right: this.state.cancelPosition }]}
onPress={() => null}
>
<Animated.Text
style={[styles.cancelSearchText, { opacity: this.state.opacity }]}
>
Cancel
</Animated.Text>
</AnimatedTouchable>
</View>
);
}
}
const styles = StyleSheet.create({
searchContainer: {
flexDirection: "row",
height: 72,
borderBottomColor: "#00000033",
paddingTop: 100
},
search: {
flex: 1,
flexDirection: "row",
height: 40,
borderRadius: 6,
backgroundColor: "red"
},
cancelSearch: {
position: "absolute",
marginHorizontal: 16,
textAlign: "center",
justifyContent: "center",
alignSelf: "center"
}
});
You're setting searchBarFocused only after your animation completes. Since the cancel button is conditionally rendered based on searchBarFocused, it only appears at the end of the animation.

How to make react native deck animation?

I making a playing card game and i want to add an deck deal animation like this:
Deal Animation
i tried change top value for Animated.Image component but output:
https://pasteboard.co/HiMc6Af.gif
i need create a clone of this component and original component should not move. But i could not put clone component over original component.
import React from 'react';
import { View, Text, Animated, TouchableOpacity } from 'react-native';
export default class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
gameStart: false,
top: new Animated.Value(-175 / 2),
};
}
componentDidMount() {}
shuffleCards(e) {
this.setState({
gameStart: true,
});
this.cycleAnimation();
}
cycleAnimation() {
Animated.loop(
Animated.sequence([
Animated.timing(this.state.top, {
toValue: -900,
duration: 300,
delay: 100,
}),
Animated.timing(this.state.top, {
toValue: -175 / 2,
duration: 1,
delay: 1,
}),
Animated.timing(this.state.top, {
toValue: 900,
duration: 300,
delay: 100,
}),
]),
{
iterations: 4,
},
).start();
}
render() {
return (
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
}}>
<TouchableOpacity>
<Animated.Image
ref={'deck'}
resizeMode="stretch"
source={require('./assets/card/back.png')}
style={[
{
width: 100,
height: 175,
},
]}
/>
</TouchableOpacity>
<TouchableOpacity onPress={e => this.shuffleCards(e)}>
<Animated.Image
resizeMode="stretch"
source={require('./assets/card/back.png')}
style={[
{
width: 100,
height: 175,
position: 'absolute',
left: -100,
},
{ top: this.state.top },
]}
/>
</TouchableOpacity>
</View>
);
}
}

Animated.loop image

Back in 1996 I created spinning logos for clients, because I could, and now in 2017 I'm back at it, thanks to Animated.
The code below the <hr /> works, but there's a tiny bump when it restarts.
Any idea how I can use Animated.loop? It doesn't: «each time it reaches the end, it resets and begins again from the start».
Animated.loop(
Animated.timing(this.state.spinValue, {
toValue: 1,
duration: this.props.duration,
easing: Easing.linear,
useNativeDriver: true
})
).start();
static defaultProps = {
duration: 60 / (33 + 1/3) * 1000
}
constructor (props) {
super(props);
this.state = {
spinValue: new Animated.Value(0)
};
}
componentDidMount () {
this._animate();
}
_animate () {
Animated.timing(this.state.spinValue, {
toValue: 1,
duration: this.props.duration,
easing: Easing.linear,
useNativeDriver: true
}).start(event => {
if (event.finished) {
this.setState({
spinValue: new Animated.Value(0)
}, this._animate.bind(this));
}
});
}
render () {
const spin = this.state.spinValue.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
});
return (
<View style={ Loading.style.container }>
<Animated.Image
source={ logo }
style={{ transform: [{ rotate: spin }] }}
/>
</View>
);
}
Easy to use react-native-LoopAnimation.js'
https://github.com/Infinity0106/react-native-LoopAnimation
import LoopAnimation from 'react-native-LoopAnimation.js'
...
render() {
//you can also use, like source={imgSource}
const imgSource=
{uri:'http://www.menucool.com/slider/jsImgSlider/images/image-slider-2.jpg',width:700,height:306};
return (
<View style={{flex:1}}>
{/*this is the background animation */}
<LoopAnimation source={require('./img/back.jpg')} duration={10000} />
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
}}>
{/*Content goes here*/}
<View style={{width: 200, height: 400, backgroundColor: 'powderblue'}} />
</View>
</View>
);
}