I am fairly new to Animated API in react native. I went through a lot of tutorials for using animation API and it seems in every one of them the elements are positioned as absolute, is it necessary to position the element absolute ?
Also I made a piece of animation but it looks glitchy, I think the view after the textinput donot have absolute as position which might be causing the issue. Is it possible to do the animation I'm trying to while keeping the textinput position absolute but other elements positioned with flexbox?
Here is the code
handleFocus = () => {
console.log('starting animation');
this.setState({
isFocused: true
});
Animated.timing(this.isFromViewFocused, {
toValue: 1,
duration: 300
}).start();
}
handleBlur = () => {
console.log('Blurring');
this.setState({
isFocused: false
});
Animated.timing(this.isFromViewFocused, {
toValue: 0,
duration: 300
}).start();
}
render() {
const labelStyle = {
position: this.state.isFocused === true ? 'absolute' : 'relative',
alignItems: 'center',
width: this.isFromViewFocused.interpolate({
inputRange: [0, 1],
outputRange: [DEVICE_WIDTH * 0.45, DEVICE_WIDTH]
}),
left: this.isFromViewFocused.interpolate({
inputRange: [0, 1],
outputRange: [DEVICE_WIDTH * 0.03, 0]
}),
marginBottom: this.isFromViewFocused.interpolate({
inputRange: [0, 1],
outputRange: [0, 80]
}),
top: this.isFromViewFocused.interpolate({
inputRange: [0, 1],
outputRange: [10, 0]
}),
borderWidth: this.isFromViewFocused.interpolate({
inputRange: [0, 1],
outputRange: [0, 5]
}),
borderColor: 'black',
paddingTop: this.state.isFocused === true ? 20 : 0
};
return (
<View style={styles.container}>
<ScrollView style={{ flex: 1 }} keyboardDismissMode='on-drag'>
<Animated.View
style={labelStyle}
>
<TextInput
onFocus={this.handleFocus}
onBlur={this.handleBlur}
style={{
borderColor: 'black',
borderWidth: 1,
width: '90%'
}}
>
<Text>Hey Text</Text>
</TextInput>
</Animated.View>
<Animated.View
style={[styles.LocationContainer,
{ marginTop: this.isFromViewFocused.interpolate({
inputRange: [0, 1],
outputRange: [20, 80]
})
}
]}>
Using absolute
positioning combined with left
, top
, bottom
, right
is bad for performances. That's why your animations looks "glitchy".
You'd be better using transforms so your component stays relative
and native optimizations can be made (same as CSS3 transforms).
Also, when using not native-optimizable properties (such as the one you use) you cannot set useNativeDriver
to true. Which makes performances even worse.
To add with that, you cannot (or shouldn't) interpolate based on a boolean. AnimatedJS provides you with an Animated.Value
class that aims to make it easier to interpolate stuff.
Here is a simpler example to Animated:
export class MyAnimatedComponent extends React.Component {
state = {
animatedValue: new Animated.Value(0);
}
focus = () => {
const { animatedValue } = this.state;
Animated.timing(animatedValue, {
duration: 280,
toValue: 1,
// This will make your animation glitch-free/performant.
useNativeDriver: true,
}).start();
}
blur = () => {
Animated.timing(animatedValue, {
duration: 140,
toValue: 0,
// This will make your animation glitch-free/performant.
useNativeDriver: true,
}).start();
}
render () {
const { animatedValue } = this.state;
const animatedStyles = {
transform: [
{
// Move the div by 120px to the left when value === 1
translateX: animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, -120],
// Tells Animated to never go outside of the outputRange
extrapolate: 'clamp',
})
},
{
translateY: animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, -50],
extrapolate: 'clamp',
})
}
]
}
return (
<View style={styles.wrapper}>
<Animated.View style={animatedStyles} onFocus={onFocus} onBlur={onBlur}>
I'm some content into an Animated div.
</Animated.View>
</View>
)
}
}