reactjs - 如何动态设置高度为动画值后动画的组件的高度?

标签 reactjs react-native react-animated

目标:有一个下拉 View ,随着时间的推移高度扩展动画。需要注意的是:一旦 View 被展开,它需要能够动态处理是否存在额外的 View 数据。如果存在,则会呈现几个额外的文本组件。

问题:就目前而言,动画将父级的高度设置为固定高度。所以当additionalContent渲染时,它超出了父级的边界,其高度是固定的。我不想不明确设置父级的高度,因为那样我就无法按照我想要的方式设置该方面的动画。我想按原样保持高度动画,并在 additionalContent 时动态调整父级以包含子级。存在

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

    const toggleDropdown = () => {
        if (expanded == true) {
            // collapse dropdown
            Animated.timing(animatedHeight, {
              toValue: 0,
              duration: 200,
            }).start()

        } else {
            // expand dropdown
             Animated.timing(animatedHeight, {
              toValue: 100,
              duration: 200,
            }).start()
        }
        setExpanded(!expanded)
    }

    const renderAdditionalContent = () => {
      setDynamicHeight(75);

      if (someVariable == true) {
        return (
          <View> <Text> Some Content </Text> </View>
        )
      }
    }

    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 + dynamicHeight }]}
        >
            <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} />

                    { renderAdditionalContent() }

                </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;

如何做到这一点?到目前为止,我尝试创建一个状态变量 dynamicHeight并将其设置在呈现附加内容的函数中,但这不起作用。

零食来了:https://snack.expo.io/P6WKioG76

澄清编辑:renderAdditionalContent 函数呈现附加内容(显然),此内容可以是从一行字符到多行的任何地方。无论字符数如何,组件的主要父容器都需要在其边界内拥有所有子容器。就目前而言,如果附加内容渲染的内容过多,内容将溢出组件的主父容器的边界,这是必须避免的。显然,这可以通过简单地不给主要组件容器提供高度来完成。但我们的想法是拥有动画高度并正确包装子内容

有什么建议?

最佳答案

这是具有动态下拉高度的代码的工作小吃:https://snack.expo.io/4mT5Xj6qF

您可以通过更改 thisIsAValue 来更改高度持续的。

老实说,您与您的代码非常接近,您只是缺少一些零碎的东西:

  • 当您为高度设置动画时,您不需要使用 interpolate ,您可以让<Animated.View>直接计算高度。如果要设置动画(例如旋转),并且需要计算元素必须移动的度数,则需要进行插值。
  • 您需要将您的动态高度传递到动画中,作为您的 to:值(value)
  • 我设置了一个简单的useEffect Hook 检查 someVariable 中的更改和 dynamicHeight Prop

  • 此解决方案将让您通过 Prop 动态设置高度。
    但是,如果您想根据 View 中存在的元素计算高度您可能想查看@vivek-doshi 的回答

    关于reactjs - 如何动态设置高度为动画值后动画的组件的高度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62367861/

    相关文章:

    react-native - 如何处理内存中的 React Native 敏感字符串信息

    animation - 使用 react-native 动画 blurRadius 属性

    react-native - native 基础页脚接受玩家在 native react 中的触摸

    react-native - react native : Animation not working properly on android

    node.js - NodeJs 在 Create React App 中导入文件

    javascript - 如何在 AsyncStorage React Native 中保存项目数组?

    css - 有没有办法在 SCSS 中不使用 !important(react + material)

    react-native - 术语 'xxd' 未被识别为 cmdlet、函数的名称

    javascript - TypeError : (0 , _react.useEffect) 不是一个函数

    javascript - 当我在设备中运行 React Native 应用程序而不通过电缆连接到电脑时,它显示 2 个月前的应用程序状态