You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native Accordion动画Bug修复求助(基于react-native-reanimated)

修复React Native Accordion组件动画卡顿问题(react-native-reanimated实现)

问题根源

当前使用{isOpen && <Content/>}的条件渲染方式,会在展开/关闭时直接挂载/卸载Content组件,导致组件先占据空间再执行动画,出现视觉不同步的卡顿。核心解决思路是避免直接卸载组件,用动画控制内容的高度和透明度,让布局变化与动画同步执行。

解决方案步骤

1. 用Reanimated共享值替代普通状态

使用useSharedValue跟踪展开状态,避免频繁触发组件重渲染,动画直接在UI线程执行,流畅度更高。

2. 始终渲染Content组件,通过动画控制显示

不再通过条件渲染挂载/卸载Content,而是用Animated.View包裹内容,通过动态修改高度、透明度实现折叠效果,同时设置overflow: 'hidden'防止内容溢出。

3. 测量Content的自然高度

为了让高度动画更精准,先获取Content的实际高度,存入共享值用于动画插值。

可选:动画结束后卸载组件(优化性能)

如果担心Content始终挂载占用资源,可以监听动画完成状态,在关闭动画结束后卸载组件。

完整代码示例

import React, { useRef, useEffect, useState } from 'react';
import { View } from 'react-native';
import Animated, { 
  useSharedValue, 
  useAnimatedStyle, 
  withTiming, 
  useAnimatedReaction,
  measure,
} from 'react-native-reanimated';

// 假设你的Header和Content组件已定义
const Header = ({ onPress }) => <View onPress={onPress}>{/* 头部内容 */}</View>;
const Content = () => <View>{/* 折叠内容 */}</View>;

const CustomAccordion = () => {
  // 共享值跟踪展开状态,替代普通useState
  const isOpen = useSharedValue(false);
  // 控制Content是否挂载(可选)
  const [showContent, setShowContent] = useState(false);
  // 测量Content高度的ref
  const contentRef = useRef(null);
  const contentHeight = useSharedValue(0);

  // 初始测量Content的自然高度
  useEffect(() => {
    measure(contentRef, (measured) => {
      if (measured) {
        contentHeight.value = measured.height;
      }
    });
  }, []);

  // 监听展开状态变化,控制Content挂载时机(可选)
  useAnimatedReaction(
    () => isOpen.value,
    (newIsOpen) => {
      if (newIsOpen) {
        setShowContent(true);
      } else {
        // 关闭动画结束后卸载Content
        setTimeout(() => {
          setShowContent(false);
        }, 1500);
      }
    }
  );

  // 创建动画样式
  const animatedContentStyle = useAnimatedStyle(() => {
    return {
      height: withTiming(isOpen.value ? contentHeight.value : 0, { duration: 1500 }),
      opacity: withTiming(isOpen.value ? 1 : 0, { duration: 1500 }),
      overflow: 'hidden',
    };
  });

  return (
    <View style={{ borderBottomWidth: 1 }}>
      <Header onPress={() => isOpen.value = !isOpen.value} />
      {/* 根据showContent控制挂载,动画过程中保持组件存在 */}
      {showContent && (
        <Animated.View ref={contentRef} style={animatedContentStyle}>
          <Content />
        </Animated.View>
      )}
    </View>
  );
};

export default CustomAccordion;

关键说明

  • 移除原代码中Accordion的layout属性,避免第三方组件布局逻辑与Reanimated动画冲突,改用自定义容器控制整体样式。
  • 共享值isOpen直接在UI线程更新,不会触发组件重渲染,动画执行更流畅。
  • 若Content内容动态变化,需在内容更新后重新测量高度,确保动画高度准确。

内容的提问来源于stack exchange,提问作者Alok Kothiyal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 17:48:21