0
点赞
收藏
分享

微信扫一扫

在 React Native 中实现可扩展卡片

七千22 2022-03-12 阅读 112

更多分享内容可访问我的个人博客

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>
举报

相关推荐

0 条评论