React-Native动画折叠式/抽屉式/下拉式/可折叠卡片

qoefvg9y  于 2022-12-04  发布在  React
关注(0)|答案(2)|浏览(114)

我想实现一个动画的可折叠列表/抽屉/下拉菜单/可折叠卡片。
动画应具有高性能,如下所示:

n3h0vuf2

n3h0vuf21#

经过大量的搜索,我可以找到许多库。但我想实现它没有任何库。而且,一些教程显示如何建立一个,但他们没有表现。
最后,这是我如何实现它的。完整的零食代码如下:https://snack.expo.dev/@vipulchandra04/a85348
我在state中存储了isOpen(无论菜单是打开还是关闭)。然后在按下按钮时改变状态。我在React-Native中使用LayoutAnimation API来动画打开和关闭列表。LayoutAnimation在本机运行动画,因此它是高性能的。

const Accordion = ({ title, children }) => {
  const [isOpen, setIsOpen] = useState(false);

  const toggleOpen = () => {
    setIsOpen(value => !value);
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
  }

  return (
    <>
      <TouchableOpacity onPress={toggleOpen} activeOpacity={0.6}>
        {title}
      </TouchableOpacity>
      <View style={[styles.list, !isOpen ? styles.hidden : undefined]}>
        {children}
      </View>
    </>
  );
};

const styles = StyleSheet.create({
  hidden: {
    height: 0,
  },
  list: {
    overflow: 'hidden'
  },
});

z3yyvxxp

z3yyvxxp2#

这样,它将修复Vipul演示的错误:如果按 accordion 太快,孩子不透明度下降到0。并添加动画图标

import {
  Animated,
  LayoutAnimation,
  Platform,
  StyleProp,
  StyleSheet,
  UIManager,
  View,
  ViewStyle,
} from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons;

if (
  Platform.OS === 'android' &&
  UIManager.setLayoutAnimationEnabledExperimental
) {
  UIManager.setLayoutAnimationEnabledExperimental(true);
}

const toggleAnimation = duration => {
  return {
    duration: duration,
    update: {
      property: LayoutAnimation.Properties.scaleXY,
      type: LayoutAnimation.Types.easeInEaseOut,
    },
    delete: {
      property: LayoutAnimation.Properties.opacity,
      type: LayoutAnimation.Types.easeInEaseOut,
    },
  };
};

interface IAccordion {
  title?: JSX.Element | JSX.Element[];
  children?: JSX.Element | JSX.Element[];
  style?: StyleProp<ViewStyle> | undefined;
}

const Accordion = ({title, children, style}: IAccordion) => {
  const [isOpen, setIsOpen] = useState(false);
  const animationController = useRef(new Animated.Value(0)).current;

  const arrowTransform = animationController.interpolate({
    inputRange: [0, 1],
    outputRange: ['0deg', '90deg'],
  });

  const onToggle = () => {
    setIsOpen(prevState => !prevState);

    const duration = 300;
    const config = {
      duration: duration,
      toValue: isOpen ? 0 : 1,
      useNativeDriver: true,
    };
    Animated.timing(animationController, config).start();
    LayoutAnimation.configureNext(toggleAnimation(duration));
  };

  return (
    <View style={style ? style : styles.accordion}>
      <TouchableOpacity onPress={onToggle} style={styles.heading}>
        {title}
        <Animated.View style={{transform: [{rotateZ: arrowTransform}]}}>
          <Ionicons name={'chevron-forward-outline'} size={18} />
        </Animated.View>
      </TouchableOpacity>
      <View style={[styles.list, !isOpen ? styles.hidden : undefined]}>
        {children}
      </View>
    </View>
  );
};

export default Accordion;

相关问题