在本机反应中正确使用动画 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 定位结合 lefttopbottomright 对性能不利。这就是为什么您的动画看起来 "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>
    )
  }
}