在本机反应中正确使用动画 API
Using the Animated API correctly in react native
我对 React Native 中的动画 API 还很陌生。我浏览了很多使用动画的教程 API,似乎每个教程中的元素都定位为绝对元素,是否有必要将元素定位为绝对元素?
我还制作了一段动画,但它看起来有问题,我认为文本输入后的视图没有绝对位置,这可能是导致问题的原因。是否可以在保持 textinput 位置绝对但其他元素使用 flexbox 定位的同时制作我正在尝试的动画?
这是代码
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]
})
}
]}>
使用 absolute
定位结合 left
、top
、bottom
、right
对性能不利。这就是为什么您的动画看起来 "glitchy".
你最好使用转换,这样你的组件就会保持 relative
并且可以进行本机优化(与 CSS3 转换相同)。
此外,当使用非本机优化的属性(例如您使用的属性)时,您不能将 useNativeDriver
设置为 true。这使得性能更差。
此外,您不能(或不应)基于布尔值进行插值。 AnimatedJS 为您提供了一个 Animated.Value
class 旨在使插入内容更容易。
这是一个更简单的动画示例:
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>
)
}
}
我对 React Native 中的动画 API 还很陌生。我浏览了很多使用动画的教程 API,似乎每个教程中的元素都定位为绝对元素,是否有必要将元素定位为绝对元素?
我还制作了一段动画,但它看起来有问题,我认为文本输入后的视图没有绝对位置,这可能是导致问题的原因。是否可以在保持 textinput 位置绝对但其他元素使用 flexbox 定位的同时制作我正在尝试的动画?
这是代码
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]
})
}
]}>
使用 absolute
定位结合 left
、top
、bottom
、right
对性能不利。这就是为什么您的动画看起来 "glitchy".
你最好使用转换,这样你的组件就会保持 relative
并且可以进行本机优化(与 CSS3 转换相同)。
此外,当使用非本机优化的属性(例如您使用的属性)时,您不能将 useNativeDriver
设置为 true。这使得性能更差。
此外,您不能(或不应)基于布尔值进行插值。 AnimatedJS 为您提供了一个 Animated.Value
class 旨在使插入内容更容易。
这是一个更简单的动画示例:
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>
)
}
}