【问题标题】:React Native: Only Animate One of Several ElementsReact Native:仅对几个元素之一进行动画处理
【发布时间】:2017-11-29 17:59:07
【问题描述】:

我创建了一个 React Native 组件,它由 5 个连续的图标组成。 这些图标是可点击的,我想为被点击的图标设置动画。

我的问题是:当我点击一个图标时,所有的图标都是动画的。这是因为它们是在循环中生成的,并且都具有相同的属性。

如何设置我的组件,以便我只能以某种方式为按下的一个图标设置动画?

这是组件:

import React from 'react';
import { StyleSheet, Animated, View, Text, TouchableHighlight, } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
const AnimatedIcon = Animated.createAnimatedComponent(Icon);

export class IconRow extends React.Component {  

  constructor(props) {
    super(props);
    this.state = { iconFontSize: new Animated.Value(50) };
  }

  onIconPress = (index) => {
    Animated.sequence([
      Animated.timing(this.state.iconFontSize, { toValue: 40, duration: 100 }),
      Animated.timing(this.state.iconFontSize, { toValue: 58, duration: 100 }),
      Animated.timing(this.state.iconFontSize, { toValue: 50, duration: 100 }),
    ]).start();
  }

  renderIcons() {
    var icons = [];
    for (var i = 0; i < 5; i++) {
      icons.push(
        <TouchableHighlight key={i} underlayColor="transparent" onPress={this.onIconPress.bind(this, i)}>       
          <AnimatedIcon name="heart" style={{fontSize:this.state.iconFontSize, color: "red"}} />
        </TouchableHighlight>   
      );        
    }
    return icons;
  }

  render() {
    return (
        <View style={{flexDirection: "row"}}>
          {this.renderIcons()}
        </View>
    );
  }
}

小吃:https://snack.expo.io/HJJ0Edhlz

【问题讨论】:

    标签: javascript animation react-native


    【解决方案1】:

    @Eric - 我无法在本地测试它,但我很确定它会做你想做的事。如果不成功,请告诉我,我将删除我的答案。

    import React from 'react';
    import { StyleSheet, Animated, View, Text, TouchableHighlight, } from 'react-native';
    import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
    const AnimatedIcon = Animated.createAnimatedComponent(Icon);
    
    export class IconRow extends React.Component {  
    
      constructor(props) {
        super(props);
        this.state = { 
          iconFontSizes: [
            new Animated.Value(50),
            new Animated.Value(50),
            new Animated.Value(50),
            new Animated.Value(50),
            new Animated.Value(50)
          ], 
        };
      }
    
      onIconPress = (i) => {
        Animated.sequence([
          Animated.timing(this.state.iconFontSizes[i], { toValue: 40, duration: 100 }),
          Animated.timing(this.state.iconFontSizes[i], { toValue: 58, duration: 100 }),
          Animated.timing(this.state.iconFontSizes[i], { toValue: 50, duration: 100 }),
        ]).start();
      }
    
      renderIcons() {
        var icons = [];
    
        for (var i = 0; i < this.state.iconFontSizes.length; i++) {
          icons.push(
            <TouchableHighlight key={i} underlayColor="transparent" onPress={this.onIconPress.bind(this, i)}>       
              <AnimatedIcon name="heart" style={{fontSize:this.state.iconFontSizes[i], color: "red"}} />
            </TouchableHighlight>   
          );        
        }
    
        return icons;
      }
    
      render() {
        return (
            <View style={{flexDirection: "row"}}>
              {this.renderIcons()}
            </View>
        );
      }
    }
    

    【讨论】:

    • 这应该可以工作,但是您需要将它们存储在一个数组中,然后使用setState 更新循环后的状态。
    • 是的,您只是不需要连接。我刚刚编辑了那部分,但其他一切看起来都不错
    • @Eric 我不能 100% 确定你可以。就像我说的,我无法在本地进行测试。
    • 好的,太棒了!您想分享您所做的编辑以便我们更新答案吗?
    • 您似乎需要至少 2K 的声望才能访问建议的编辑审核队列,所以我无法批准它,但有人会批准。很高兴这成功了。祝你的项目好运。感谢@Matt Aft 在这方面的合作。
    【解决方案2】:

    在这里,您正在创建整行图标,这就是您遇到此问题的原因。

    在这里,您必须一次创建一个图标,而不是创建一行。 比如,用一个视图来创建一个图标并设置在一行中

    <View style = {{flexDirection:'row'}} >
        <IconRow />
        <IconRow />
        <IconRow />
        <IconRow />
        <IconRow />
    </View>
    

    之后,IconRow 类中的 renderIcons 函数,移除 for 循环和依赖变量 'i' like,

    icons.push(
            <TouchableHighlight key={1} underlayColor="transparent" onPress={this.onIconPress.bind(this, 1)}>       
              <AnimatedIcon name="heart" style={{fontSize:this.state.iconFontSize, color: "red"}} />
            </TouchableHighlight> 
    );
    

    或者你可以只迭代一次for循环,

    for (var i = 0; i < 1; i++) {
          icons.push(
            <TouchableHighlight key={1} underlayColor="transparent" onPress={this.onIconPress.bind(this, 1)}>       
              <AnimatedIcon name="heart" style={{fontSize:this.state.iconFontSize, color: "red"}} />
            </TouchableHighlight> 
          );
    }
    

    因此它一次只创建一个图标并连续创建一个图标。如果您想提供不同的密钥,请将“1”更改为另一个值。

    现在动画被点击的那个。

    希望对您有所帮助。

    【讨论】:

    • 所以基本上你的意思是为带有动画的图标制作一个单独的组件?是的,我相信这会起作用,但是我更喜欢上面的答案。谢谢!
    【解决方案3】:

    这是因为你调用的是同一个函数,每次调用都有相同的引用。创建一个新组件并在该组件中循环,以便每个图标都有自己的功能和不同的引用。

    这将是 Icon 的组件

    const Icon = ({ i }) => {
        const iconFontSize = new Animated.Value(50)
    
        const onIconPress = () => {
            Animated.sequence([
              Animated.timing(iconFontSize, { toValue: 40, duration: 100 }),
              Animated.timing(iconFontSize, { toValue: 58, duration: 100 }),
              Animated.timing(iconFontSize, { toValue: 50, duration: 100 }),
         ]).start();}
    
    
    
        return (
            <TouchableHighlight key={i} underlayColor="transparent" onPress {onIconPress}>       
              <AnimatedIcon name="heart" style={{fontSize: iconFontSize, color: "red"}} />
            </TouchableHighlight>   
        )
    }
    

    Bellow 将是父组件,您将在其中导入上述 Icon 组件并在其上循环。现在,在每个循环中,您将拥有一个组件和仅与该组件关联的动画函数。

    const IconRow = ({ }) => {
        renderIcons = () => {
          var icons = [];
          for (var i = 0; i < 5; i++) {
            icons.push(<Icon i={ i } />);        
          }
          return icons;
        }
    
        return (
            <View style={{flexDirection: "row"}}>
              {renderIcons()}
            </View> 
        )
    }
    

    【讨论】:

      猜你喜欢
      • 2021-07-10
      • 1970-01-01
      • 1970-01-01
      • 2020-03-24
      • 2016-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-21
      相关资源
      最近更新 更多