当列表视图项来自数据源 added/removed 时,对它们进行动画处理

Animate listview items when they are added/removed from datasource

谁能告诉我如何做到这一点,例如添加动画时高度从 0 开始,删除时返回 0?

添加动画很容易,只需将 Animated in componentDidMount 与您的 listRow 一起使用,例如:

componentDidMount = ()=> {
    Animated.timing(this.state._rowOpacity, {
        toValue: 1,
        duration: 250,
    }).start()
}

在 react-native 中,在卸载之前为组件设置动画要困难得多。您应该为 ListView 设置处理程序。当数据源改变时,区分数据,启动动画以隐藏删除的行,并为 ListView.

设置新的数据源

在这里您可以获得不透明动画的完整工作示例:

import React from 'react-native';

export default class Cell extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            opacity: new React.Animated.Value(0)
        };
    }

    componentDidMount() {
        React.Animated.timing(this.state.opacity, {
            toValue: 1,
            duration: 250,
        }).start();
    }

    render() {
        return (
            <React.Animated.View style={[styles.wrapper, {opacity: this.state.opacity}]}>
                <React.Image source={{uri: 'http://placehold.it/150x150'}} style={styles.image}/>
                <React.Text style={styles.text}>
                    Text
                </React.Text>
            </React.Animated.View>
        );
    }
}

const styles = React.StyleSheet.create({
    wrapper: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'flex-start',
        alignItems: 'center',
    },
    image: {
        height: 40,
        width: 40,
        marginRight: 16,
        backgroundColor: '#C9D5E6'
    },
    text: {
        fontSize: 20
    }
});

如果您需要从列表中删除项目,请按以下步骤操作 ListRow 组件:

class DynamicListRow extends Component {
   // these values will need to be fixed either within the component or sent through props
   _defaultHeightValue = 60;
   _defaultTransition  = 500;
   state = {
       _rowHeight  : new Animated.Value(this._defaultHeightValue),
       _rowOpacity : new Animated.Value(0)
   };
   componentDidMount() {
       Animated.timing(this.state._rowOpacity, {
           toValue  : 1,
           duration : this._defaultTransition
       }).start()
   }
   componentWillReceiveProps(nextProps) {
       if (nextProps.remove) {
           this.onRemoving(nextProps.onRemoving);
       } else {
// we need this for iOS because iOS does not reset list row style properties
           this.resetHeight()
       }
   }
   onRemoving(callback) {
       Animated.timing(this.state._rowHeight, {
           toValue  : 0,
           duration : this._defaultTransition
       }).start(callback);
   }
   resetHeight() {
       Animated.timing(this.state._rowHeight, {
           toValue  : this._defaultHeightValue,
           duration : 0
       }).start();
   }
   render() {
       return (
           <Animated.View
               style={{height: this.state._rowHeight, opacity: this.state._rowOpacity}}>
               {this.props.children}
           </Animated.View>
       );
   }
}

我已经 post 在此博客 post 中针对这个问题编写了完整的教程。它逐步解释了您需要做什么来完成添加和删除项目以及动画此过程。 添加非常简单,但删除看起来有点复杂。 http://moduscreate.com/react-native-dynamic-animated-lists/

这是高度和不透明度动画的完整示例。它支持添加和删除元素。关键是你需要在消失动画完成后重新设置高度和不透明度。然后您立即从源中删除该项目。

export const ListItem = (props: ListItemProps) => {
  // Start the opacity at 0
  const [fadeAnim] = useState(new Animated.Value(0));

  // Start the height at 0
  const [heightAnim] = useState(new Animated.Value(0));

  /**
   * Helper function for animating the item
   * @param appear - whether the animation should cause the item to appear or disappear
   * @param delay - how long the animation should last (ms)
   * @param callback - callback to be called when the animation finishes
   */
  const _animateItem = (appear: boolean = true, delay: number = 300, callback: () => void = () => null) => {
    Animated.parallel([
      Animated.timing(
        fadeAnim,
        {
          toValue: appear ? 1 : 0,
          duration: delay,
        }
      ),
      Animated.timing(
        heightAnim,
        {
          toValue: appear ? 100 : 0,
          duration: delay,
        }
      ),
    ]).start(callback);
  };

  // Animate the appearance of the item appearing the first time it loads
  // Empty array in useEffect results in this only occuring on the first render
  React.useEffect(() => {
    _animateItem();
  }, []);

  // Reset an item to its original height and opacity
  // Takes a callback to be called once the reset finishes
  // The reset will take 0 seconds and then immediately call the callback.
  const _reset = (callback: () => void) => {
    _animateItem(true,0, callback);
  }

  // Deletes an item from the list. Follows the following order:
  // 1) Animate the item disappearing. On completion:
  // 2) Reset the item to its original display height (in 0 seconds). On completion:
  // 3) Call the parent to let it know to remove the item from the list
  const _delete = () => {
    _animateItem(false, 200, () => _reset(props.delete));
  };

  return (
      <Animated.View
        style={{height: heightAnim, opacity: fadeAnim, flexDirection: 'row'}}>
        <Text>{props.text}</Text>
        <Button onPress={() => _delete()}><Text>Delete</Text></Button>
      </Animated.View>
  );
}