"Animated.createAnimatedComponent" 是如何工作的?

28
在组件 ProgressBarAndroid 中,有一个名为 indeterminable={Boolean} 的属性,它向用户展示了正在进行的动画。我想在 ProgressViewIOS 上实现几乎相同的效果。因此,我尝试使用 Animated 来进行动画处理...

我在 Animated 的文档中看到了一个名为 'createAnimatedComponent' 的方法,他们用它来创建 Animated.View

我尝试创建另一个 Animated(Native)组件,但是它根本不起作用。 该动画应逐渐将 fillValue 提高到 20%,然后继续使用媒体上传的原始值...

这是我的组件:

// ProgressBar.ios.js
// @flow
import { PropTypes } from 'react';
import Component from 'components/base/Component';
import { ProgressViewIOS, Animated } from 'react-native';

const AnimatedProgressViewIOS = Animated.createAnimatedComponent(ProgressViewIOS);

class ProgressBarIOS extends Component {

  static propTypes = {
    // Percentage (0 - 100)
    fill: PropTypes.number.isRequired,
  };

  constructor(props, context: any) {
    super(props, context);
    this.state = {
      fillValue: new Animated.Value(props.fill),
    };
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.fill === 0) {
      Animated.timing(this.state.fillValue, { toValue: 0.2, duration: 500 }).start();
    } else if (nextProps.fill > 19) {
      this.state.fillValue.setValue(nextProps.fill / 100);
    }
  }

  shouldComponentUpdate(nextProps) {
    return this.props.fill !== nextProps.fill;
  }

  render() {
    return (
      <AnimatedProgressViewIOS
        style={{ alignSelf: 'stretch' }}
        progress={this.state.fillValue} />
    );
  }

}

export default ProgressBarIOS;

编辑:AnimatedComponent仅用于修改样式。可以将道具作为动画值传递,但请记住它不是数字!


对你来说它渲染出了什么?对我来说,当我用可动画组件包装我的组件时,它就消失了。 - Waltari
7
我通过将我想要动画的组件包装在一个 "<Animated.View>" 标签中,并将动画应用于其样式来解决这个问题。不确定这是否会对你有所帮助... - Waltari
1个回答

2
Animated.createAnimatedComponent 可以对多种不同的属性进行动画处理,但是只有一些属性支持使用本地驱动程序进行处理。幸运的是,在 ProgressViewIOS 上,progress 属性似乎就是其中之一。
这里是一个带有动画效果的 ProgressViewIOS可行实现
import * as React from 'react';
import { View, SafeAreaView } from 'react-native';
import { ProgressViewIOS, Animated } from 'react-native';

const AnimatedProgressViewIOS = Animated.createAnimatedComponent(
  ProgressViewIOS
);

export default function App() {
  const value = React.useRef(new Animated.Value(0));

  React.useEffect(() => {
    Animated.loop(
      Animated.timing(value.current, {
        duration: 2000,
        toValue: 1,
        useNativeDriver: true,
      })
    ).start();
  }, []);

  return (
    <SafeAreaView>
      <View style={{ padding: 20 }}>
        <AnimatedProgressViewIOS
          style={{ alignSelf: 'stretch' }}
          progress={value.current}
        />
      </View>
    </SafeAreaView>
  );
}

值得注意的是,ProgressViewIOS 现在已弃用,但构建自己的进度条视图非常简单,只需要两个 View 并添加像这样的简单样式 (expo snack):
import * as React from 'react';
import { View, SafeAreaView, StyleSheet, Button, Text } from 'react-native';
import { Animated } from 'react-native';

export default function App() {
  const [progress, setProgress] = React.useState(() => Math.random());

  return (
    <SafeAreaView>
      <View style={{ padding: 20 }}>
        <AnimatedProgressView progress={progress} />
        <Text style={{padding: 20, textAlign: 'center'}}>{Math.round(progress * 100)}%</Text>
        <Button title="Animate" onPress={() => setProgress(Math.random())} />
      </View>
    </SafeAreaView>
  );
}

function AnimatedProgressView({ progress, style }) {
  const value = React.useRef(new Animated.Value(0));
  const [width, setWidth] = React.useState(0);

  React.useEffect(() => {
    Animated.spring(value.current, { toValue: progress }).start();
  }, [progress]);

  return (
    <View
      style={[styles.track, style]}
      onLayout={(event) => setWidth(event.nativeEvent.layout.width)}>
      <Animated.View
        style={[
          styles.fill,
          {
            transform: [
              {
                translateX: value.current.interpolate({
                  inputRange: [0, 1],
                  outputRange: [-width, 0],
                  overflow: 'clamp',
                }),
              },
            ],
          },
        ]}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  track: {
    minHeight: 4,
    borderRadius: 2,
    overflow: 'hidden',
    backgroundColor: '#ddd',
  },
  fill: {
    ...StyleSheet.absoluteFillObject,
    backgroundColor: 'blue',
  },
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接