mail: vnovick@gmail.com
twitter: @VladimirNovick
github: vnovick
facebook: vnovickdev
LayoutAnimation = Native
Animated = requestAnimationFrame
Pros:
Cons:
Pros:
Cons:
// enable layout animation for Android in component constructor
if (Platform.OS === 'android') {
UIManager
.setLayoutAnimationEnabledExperimental(true)
}
Just works
LayoutAnimation
onPress(index) {
const {
easeInEaseOut,
spring,
linear
} = LayoutAnimation.Presets;
LayoutAnimation.configureNext(
easeInEaseOut
// spring
// linear
)
this.setState({ index });
}
renderButton(index) {
return (
<TouchableOpacity
key={'button' + index}
style={styles.button}
onPress={() => this.onPress(index)}>
<Text>{index}</Text>
</TouchableOpacity>
);
}
render() {
const { redStyle, greenStyle, blueStyle } = this.getStyleByIndex(this.state.index)
return (
<View style={styles.container}>
<View style={styles.topButtons}>
{this.renderButton(0)}
{this.renderButton(1)}
{this.renderButton(2)}
</View>
<View style={styles.content}>
<View style={{flexDirection: 'column', flex: 1}}>
<View style={[redStyle, {backgroundColor: 'red'}]}/>
<View style={[greenStyle, {backgroundColor: 'green'}]}/>
<View style={[blueStyle, {backgroundColor: 'blue'}]}/>
</View>
</View>
</View>
);
}
easeInEaseOut Preset
easeInEaseOut: create(
300, Types.easeInEaseOut, Properties.opacity
)
Property to animate out of:
Type of animation out of:
TypesEnum = {
spring: true,
linear: true,
easeInEaseOut: true,
easeIn: true,
easeOut: true,
keyboard: true,
}
PropertiesEnum = {
opacity: true,
scaleXY: true,
};
duration
Linear Preset
linear: create(
500, Types.linear, Properties.opacity
)
spring Preset
spring: {
duration: 700,
create: {
type: Types.linear,
property: Properties.opacity,
},
update: {
type: Types.spring,
springDamping: 0.4,
},
delete: {
type: Types.linear,
property: Properties.opacity,
},
}
const CustomLayoutAnimation = {
duration: 1000,
create: {
delay: 1000,
type: LayoutAnimation.Types.spring,
property: LayoutAnimation.Properties.scaleXY,
springDamping: 0.2,
initialVelocity: 1
},
update: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.scaleXY
},
delete: {
type: LayoutAnimation.Types.easeOut,
property: LayoutAnimation.Properties.opacity
},
};
Animation to execute on initial render
Animation to execute state update
Animation to execute when component is destroyed
onPress(index) {
LayoutAnimation.configureNext(CustomLayoutAnimation);
this.setState({index: index});
}
renderButton(index) {
return (
<TouchableOpacity key={'button' + index} style={styles.button} onPress={() => this.onPress(index)}>
<Text>{index + 1}</Text>
</TouchableOpacity>
);
}
renderCircle(key) {
var size = 50;
return (
<View key={key} style={{width: size, height: size, borderRadius: size / 2.0, backgroundColor: 'yellow', margin: 20}}/>
);
}
render() {
var circles = [];
for (var i = 0; i < (1 + this.state.index); i++) {
circles.push(this.renderCircle(i));
}
return (
<View style={styles.container}>
<View style={styles.topButtons}>
{this.renderButton(0)}
{this.renderButton(1)}
{this.renderButton(2)}
</View>
<View style={styles.content}>
<View style={styles.circleContainer}>
{circles}
</View>
</View>
</View>
);
}
Utilizes requestAnimationFrame to animate the values and setNativeProps in order to send values to the native world
Animated value types:
Animated components
Animated.Value
Animated.ValueXY
timing/spring/decay/sequence/parallel/stagger/delay/event
Animated functions:
In order to create a simple value that can be animated we need to create a new value with
new Animated.Value(0)
Value cannot be object or array. It must be simple value.
Actual value is shielded inside Animated.Value and can be passed to style or other native prop on Animated components
Important!
class Circle extends Component {
constructor(props){
super(props);
this.state = {
opacity: new Animated.Value(0)
}
}
componentDidMount(){
Animated.timing(
this.state.opacity,
{
toValue: 50,
duration: 10000
}
).start();
}
render(){
let size = 50;
const circleStyle = {
width: size,
height: size,
borderRadius: size / 2,
backgroundColor: 'coral',
margin: 20
}
return (
<Animated.View
key={this.props.id}
style={{
...circleStyle,
opacity: this.state.opacity
}}
/>
);
}
}
In order to create a {x: 0, y:0 } value that can be animated we need to create a new value with
new Animated.ValueXY({x: 0, y: 0})
Usually used when dealing with component position/gestures
Actual value is shielded inside Animated.ValueXY and can be passed to style or other native prop on Animated components
Reasons to use
getLayout() ->
getTranslateTransform() ->
{
left: this._animatedValue.x,
top: this._animatedValue.y
}
{transform: [
{
translateX:
this._animatedValue.x
},
{
translateY:
this._animatedValue.y
}
]}
setOffset - sets base offset above value. This method is also present in Animated.Value
Interpolate is a function that gives us ability to bind to Animated.Value and change our output.
constructor(props){
super(props);
this._animatedXY = new Animated.ValueXY({ x: 0, y: 0});
}
componentDidMount(){
Animated.timing(
this._animatedXY,
{
toValue: 100,
duration: 1000
}).start();
}
render(){
let size = 50;
const circleStyle = {
width: size,
height: this._animatedXY.y.interpolate({
inputRange: [0, 100],
outputRange: [0, 50]
}),
borderRadius: size / 2,
margin: 20,
backgroundColor: this._animatedXY.x.interpolate({
inputRange: [0, 100],
outputRange: ['coral', 'blue']
})
}
return (
<Animated.View
key={this.props.id}
style={{
...circleStyle
}}
/>
);
}
When interpolating values you have to specify how to extrapolate them.
Three types of extrapolation:
componentDidMount(){
Animated.timing(
this._animatedXY,
{
toValue: 1000,
duration: 1000
}
).start();
}
render(){
let size = 50;
const circleStyle = {
width: size,
height: this._animatedXY.y.interpolate({
inputRange: [0, 100],
outputRange: [0, 50],
extrapolate: 'extend',
// extrapolate: 'clamp',
// extrapolate: 'identity',
}),
borderRadius: size / 2,
margin: 20,
backgroundColor: this._animatedXY.x.interpolate({
inputRange: [0, 100],
outputRange: ['coral', 'blue']
})
}