Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/react-native/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 为什么只运行一个react本机并行动画,而不运行另一个?_Reactjs_React Native_React Animated - Fatal编程技术网

Reactjs 为什么只运行一个react本机并行动画,而不运行另一个?

Reactjs 为什么只运行一个react本机并行动画,而不运行另一个?,reactjs,react-native,react-animated,Reactjs,React Native,React Animated,目标是: 创建一个下拉视图,折叠时高度为75px。展开时,其高度为225px。按下启动动画的按钮时,将并行运行两个动画,一个用于高度的计时功能,另一个用于不透明度。目标的第二部分是设置下拉列表下半部分的不透明度的动画,使其在expanded==true上可用 问题是: 展开视图时,动画按预期运行,没有问题。但是当折叠下拉列表时,似乎只有不透明度动画运行。问题在于高度没有正确反映在视图中。它与展开时保持相同的高度 以下是组件: const ListItem = (props) => {

目标是:

创建一个下拉视图,折叠时高度为75px。展开时,其高度为225px。按下启动动画的按钮时,将并行运行两个动画,一个用于高度的计时功能,另一个用于不透明度。目标的第二部分是设置下拉列表下半部分的不透明度的动画,使其在
expanded==true
上可用

问题是:

展开视图时,动画按预期运行,没有问题。但是当折叠下拉列表时,似乎只有不透明度动画运行。问题在于高度没有正确反映在视图中。它与展开时保持相同的高度

以下是组件:

const ListItem = (props) => {
    const [checkInModal, setCheckInModal] = useState(false);
    const [animatedHeight, setAnimatedHeight] = useState(new Animated.Value(0))
    const [animatedOpacity] = useState(new Animated.Value(0))
    const [expanded, setExpanded] = useState(false);

    const toggleDropdown = () => {
        console.log("BEFORE ANIMATION =>" + "\n" + "expanded: " + expanded + "\n" + "animatedHeight: " + JSON.stringify(animatedHeight) + "\n" + "animatedOpacity: " + JSON.stringify(animatedOpacity))
        if (expanded == true) {
            // collapse dropdown
            Animated.parallel([
                Animated.timing(animatedHeight, {
                    toValue: 0,
                    duration: 200,
                }),
                Animated.timing(animatedOpacity, {
                    toValue: 0,
                    duration: 400,
                })
            ]).start()
            setTimeout(() => console.log("AFTER ANIMATION =>" + "\n" + "animatedHeight: " + JSON.stringify(animatedHeight) + "\n" + "animatedOpacity: " + JSON.stringify(animatedOpacity)), 3000)
            // This alone works properly*
            // Animated.timing(animatedHeight, {
            //  toValue: 0,
            //  duration: 200,
            // }).start()

        } else {
            // expand dropdown
            Animated.sequence([
                Animated.timing(animatedHeight, {
                    toValue: 100,
                    duration: 200,
                }),
                Animated.timing(animatedOpacity, {
                    toValue: 100,
                    duration: 400,
                })
            ]).start()
            setTimeout(() => console.log("AFTER ANIMATION =>" + "\n" + "animatedHeight: " + JSON.stringify(animatedHeight) + "\n" + "animatedOpacity: " + JSON.stringify(animatedOpacity)), 3000)
            // This alone works properly*
            // Animated.timing(animatedHeight, {
            //  toValue: 100,
            //  duration: 200,
            // }).start()
        }
        setExpanded(!expanded)
    }

    const interpolatedHeight = animatedHeight.interpolate({
        inputRange: [0, 100],
        outputRange: [75, 225]
    })

    const interpolatedOpacity = animatedOpacity.interpolate({
        inputRange: [0, 100],
        outputRange: [0.0, 1.0]
    })

    return (
        <Animated.View
            style={[styles.container, { height: interpolatedHeight }]}
        >
            <View style={{ flexDirection: 'row', justifyContent: 'space-between', }}>
                <View style={styles.leftContainer}>
                    <View style={{ flexDirection: 'row', alignItems: 'center' }}>
                        <Text style={styles.title}>{props.title}</Text>
                    </View>
                    <Text style={styles.subtitle}>{time()}</Text>
                </View>

                <View style={styles.rightContainer}>
                    <TouchableOpacity onPress={() => toggleDropdown()} style={styles.toggleBtn}>
                        <Image source={require('../assets/img/chevron-down.png')} resizeMode={'contain'} style={styles.chevron} />
                    </TouchableOpacity>
                </View>
            </View>

            {expanded == true ? (
                <Animated.View style={[styles.bottomContainer, { opacity: interpolatedOpacity }]}>
                    <Components.BodyText text="Subject:" style={{ fontFamily: Fonts.OPENSANS_BOLD }} />

                    <Components.BodyText text={props.subject} />
                </Animated.View>
            ) : null}
        </Animated.View>
    );
};

const styles = StyleSheet.create({
    container: {
        backgroundColor: '#fff',
        borderRadius: 25,
        width: width * 0.95,
        marginBottom: 5,
        marginHorizontal: 5,
        paddingVertical: 15,
        paddingHorizontal: 15
    },
    leftContainer: {
        justifyContent: 'space-between',
    },
    rightContainer: {
        flexDirection: 'row',
        alignItems: 'center'
    },
    title: {
        fontFamily: Fonts.OPENSANS_BOLD,
        fontSize: 20,
        color: '#454A66'
    },
    subtitle: {
        color: '#454A66',
        fontSize: 14
    },
    typeIcon: {
        height: 25,
        width: 25
    },
    chevron: {
        height: 15,
        width: 15
    },
    toggleBtn: {
        borderWidth: 1,
        borderColor: Colors.PRIMARY_DARK,
        borderRadius: 7,
        paddingTop: 4,
        paddingBottom: 2.5,
        paddingHorizontal: 4,
        marginLeft: 10
    },
    bottomContainer: {
        marginVertical: 20
    },
    buttonContainer: {
        flexDirection: 'row',
        width: 250,
        justifyContent: 'space-between',
        alignSelf: 'center',
        marginVertical: 20
    },
    noShadow: {
        elevation: 0,
        shadowOffset: {
            width: 0,
            height: 0
        },
        shadowRadius: 0,
    }
});

export default ListItem;
展开时,按下按钮折叠会在控制台中记录此内容:

 LOG  BEFORE ANIMATION =>
expanded: false
animatedHeight: 0
animatedOpacity: 0
 LOG  AFTER ANIMATION =>
animatedHeight: 100
animatedOpacity: 100
 LOG  BEFORE ANIMATION =>
expanded: true
animatedHeight: 100
animatedOpacity: 100
 LOG  AFTER ANIMATION =>
animatedHeight: 100
animatedOpacity: 100
不太清楚这是关于什么的,就像我说的那样,不透明动画在折叠和扩展时工作。如果除了将高度动画从
Animated.parallel()
中取出外,完全不接触高度动画,则高度动画在展开和折叠时会按预期工作


对这里发生的事情有什么想法吗?

当您尝试设置不再渲染的对象的动画时,问题就出现了。显然,如果其中一个元素不再存在,则整个
动画.parallel
块将无法工作。如果一个动画停止,则
Animated.parallel
中的所有动画都将停止。您可以使用
stopTogether
标志覆盖此行为:

    const toggleDropdown = () => {
        if (expanded === true) {
            // collapse dropdown
            Animated.parallel([
                Animated.timing(animatedHeight, {
                    toValue: 0,
                    duration: 200,
                }),
                Animated.timing(animatedOpacity, {
                    toValue: 0,
                    duration: 400,
                })
            ], { stopTogether: false }).start()
            // ...

当您尝试折叠下拉列表时,
expanded
标志设置为
false
,使“subject”组件不再渲染,从而使整个动画失败。展开下拉列表时,
expanded
标志设置为
true
,组件现在被渲染,动画工作,但这并不重要,因为它以前没有返回原始值

尝试删除条件呈现
expanded==true?
部分(我认为它不会影响实际输出)。我尝试过你的代码,但没有它,似乎工作

另一个选项是在展开下拉列表之前
setExpanded(true)
,以使元素可见并准备设置动画(并在折叠动画结束时将其设置为false):

您将面临一些视觉问题(“主题”部分显示在组件外部,也许您应该添加一个
溢出:隐藏
或更改计时)。但是动画问题应该得到解决。

给你

动画有两个问题:

  • 折叠动画时,使不透明度为0 受尊重的元素已消失,因此您可以在折叠时设置超时 一旦动画完成,就可以移除元素, 我们需要这样做只是为了删除,因为在扩展时,我们需要 元素尽快返回,因此在检查时不需要设置超时
  • 默认情况下,如果其中一个动画停止,则所有动画都将停止。您可以使用 停在一起旗
  • //在数组中获取动画时间帧
    常数animationDurations=[5001000];
    const[checkInModal,setCheckInModal]=useState(false);
    const[animatedHeight,setAnimatedHeight]=useState(新的Animated.Value(0))
    常量[animatedOpacity]=useState(新的Animated.Value(0))
    const[expanded,setExpanded]=useState(false);
    常量切换下拉列表=()=>{
    如果(扩展==true){
    平行动画([
    动画。计时(动画高度{
    toValue:0,
    持续时间:动画持续时间[0],
    }),
    动画。计时(动画容量{
    toValue:0,
    持续时间:动画持续时间[1],
    })
    ], {
    stopTogether:false//{
    setExpanded(!expanded)
    },Math.max(…animationDurations));
    }否则{
    //展开下拉列表
    动画序列([
    动画。计时(动画高度{
    toValue:100,
    持续时间:动画持续时间[0],
    }),
    动画。计时(动画容量{
    toValue:100,
    持续时间:动画持续时间[1],
    })
    ]).start()
    
    setExpanded(!expanded)//虽然我标记了正确答案并奖励了另一个答案,但我发布了我实现的代码,实现了所需的功能。正如@Vivek Doshi在我的另一篇文章中指出的,
    useffect()
    对我的努力大有帮助

    我更改的两个主要内容是在切换功能中切换一个简单的布尔值:

    const toggleTest = () => {
        setExpanded(!expanded)
    }
    
    和实现useffect():


    请确保向useEffect参数添加适当的依赖项!

    bounty,因为您首先回答了问题。但是,我没有使用此解决方案。我最终使用useEffect()实现取而代之的是以某种方式解决了我的问题被选中的原因:1)它首先解决了问题。2)他们首先发布。仅仅因为我最终在实施中走了一条不同的路线,并不意味着答案无效。@VivekDoshi
      // take the animation timeframe in array
      const animationDurations = [500, 1000];
      const [checkInModal, setCheckInModal] = useState(false);
      const [animatedHeight, setAnimatedHeight] = useState(new Animated.Value(0))
      const [animatedOpacity] = useState(new Animated.Value(0))
      const [expanded, setExpanded] = useState(false);
    
      const toggleDropdown = () => {
        if (expanded == true) {
          Animated.parallel([
            Animated.timing(animatedHeight, {
              toValue: 0,
              duration: animationDurations[0],
            }),
            Animated.timing(animatedOpacity, {
              toValue: 0,
              duration: animationDurations[1],
            })
          ], {
            stopTogether: false // <--- so that all animation get completed
          }).start()
    
          // get max animation time and then toggle the element out
          setTimeout(() => {
            setExpanded(!expanded)
          }, Math.max(...animationDurations));
    
        } else {
          // expand dropdown
          Animated.sequence([
            Animated.timing(animatedHeight, {
              toValue: 100,
              duration: animationDurations[0],
            }),
            Animated.timing(animatedOpacity, {
              toValue: 100,
              duration: animationDurations[1],
            })
          ]).start()
    
          setExpanded(!expanded) // <---- Toggle asap to for showing purpose
        }
      }
    
      const interpolatedHeight = animatedHeight.interpolate({
        inputRange: [0, 100],
        outputRange: ["0%", "100%"]
      })
    
    const toggleTest = () => {
        setExpanded(!expanded)
    }
    
    const ListItem = (props) => {
    
    const [checkInModal, setCheckInModal] = useState(false);
    const [animatedHeight] = useState(new Animated.Value(75))
    const [animatedOpacity] = useState(new Animated.Value(0))
    const [dynamicHeight, setDynamicHeight] = useState(0);
    const [expanded, setExpanded] = useState(false);
    
    useEffect(() => {
        if (expanded) {
            // expand dropdown
            Animated.parallel([
                Animated.timing(animatedHeight, {
                    toValue: 225 + dynamicHeight,
                    duration: 200,
                }),
                Animated.timing(animatedOpacity, {
                    toValue: 100,
                    duration: 200,
                })
            ]).start()
        } else {
            Animated.parallel([
                Animated.timing(animatedHeight, {
                    toValue: 75,
                    duration: 200,
                }),
                Animated.timing(animatedOpacity, {
                    toValue: 0,
                    duration: 400,
                })
            ]).start()
        }
    }, [dynamicHeight, expanded])