更多分享内容可访问我的个人博客
https://www.niuiic.top/
本文介绍如何在 react native 中自定义一个可以通过点击展开收起的容器,本文中将其称为可扩展卡片。
实现方式
说一下实现思路。
首先,这个卡片应当有两个状态,即展开和收起状态,那么一定有一个描述状态的变量,点一下按钮可以切换变量的值。
然后,在收起状态下,子组件应当不显示,展开状态下子组件显示。要达成这样的效果有很多种方法。比如{isHidden ? children : null}
,或者改变组件高度。这样做的效果就是卡片展开与收起时没有动画效果。
那么如何实现动画效果呢?这也有很多种方法。先介绍一种简单的,逐步改变高度。只需要在useEffect
中设置一个定时器,定时增加或者减少子组件的高度,然后令包裹子组件的组件的overflow="hidden"
就可以实现简易的动画效果。具体步骤就不讲了。另一种是利用Animated
组件。
以下为源码,关键步骤看注释。
import { Text, View, TouchableOpacity, Animated } from "react-native";
import { useState, useRef } from "react";
const Header = () => {
return <Text>toggle</Text>;
};
const ExpandableCard = ({ duration = 500, header = Header, ...props }) => {
const animation = useRef(new Animated.Value(0)).current;
const [isHidden, setHidden] = useState(true);
const [childHeight, setChildHeight] = useState(0);
const toggleHidden = () => {
setHidden(!isHidden);
Animated.timing(animation, {
toValue: isHidden ? 1 : 0,
// 设置动画持续时间
duration: duration,
useNativeDriver: false,
}).start();
};
return (
<View>
<TouchableOpacity
onPress={() => {
toggleHidden();
}}
activeOpacity={1}
>
{
// 这里是自定义的卡片header,也就是点击的地方
// 默认就是前面的Header
header()
}
</TouchableOpacity>
// 动画效果
<Animated.View
style={{
height: animation.interpolate({
// 输入 输出
// 0 0.1
// 1 子组件高度
// 这里输入的0和1是上面Animated.timing中设置的
// 一开始的高度如果设置为0,则子组件的高度一直为0
// 设置为0.1,子组件的高度会慢慢增加,最终达到真实高度
// 如果想知道具体过程,可以在下面的onLayout中的函数中打印height
inputRange: [0, 1],
outputRange: [0.1, childHeight],
}),
overflow: "hidden",
}}
>
<View
onLayout={(event) => {
const { height } = event.nativeEvent.layout;
setChildHeight(height);
}}
>
// 这里是传入的子组件
{props.children}
</View>
</Animated.View>
</View>
);
};
export default ExpandableCard;
以上只是一个简单实现,原理已经完全体现了,想要更多的功能可以自己完善。
使用
用法很简单,可以传入自定义的头部,也可以设置动画时间。
<ExpandableCard header={CustomHeader} duration={1000}>
childComponent
</ExpandableCard>