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

Expo嵌套横向FlatList动态高度适配问题求助

训练动作列表替换项高度动态调整问题

问题描述

正在开发训练动作列表功能,核心需求是部分动作可设置替换项:

  • 所有动作通过垂直FlatList展示,替换项采用横向FlatList承载,基础展示功能正常。
  • 核心问题:每个动作的组数不同,导致单个项的高度有差异;用户横向滚动切换替换项时,嵌套的横向FlatList高度无法随当前激活项动态调整。
  • 尝试通过计算每个横向项的高度,切换激活索引时动态设置列表高度,但触发了布局报错。

相关代码

WorkoutExerciseList(垂直滚动列表)

const renderItem = useCallback(
  ({
    item,
    drag,
    isActive,
  }: RenderItemParams<WorkoutExercise | WorkoutExercise[]>) => {
    if (Array.isArray(item) && item.length >= 2) {
      return (
        <ReplacementExercisesList
          items={item}
          drag={drag}
          displaySetFinishedHeaderIcon={displaySetFinishedHeaderIcon}
        />
      );
    } else if (Array.isArray(item)) {
      return (
        <WorkoutExercisesListItem
          {...item[0]}
          drag={drag}
          displaySetFinishedHeaderIcon={displaySetFinishedHeaderIcon}
        />
      );
    } else {
      return (
        <WorkoutExercisesListItem
          {...item}
          drag={drag}
          displaySetFinishedHeaderIcon={displaySetFinishedHeaderIcon}
        />
      );
    }
  },
  []
);

<DraggableFlatList
  contentContainerStyle={{
    // flexGrow: 1,
    // flex: 1,
    paddingBottom: 160,
  }}
  keyboardShouldPersistTaps="handled"
  // style={{ flex: 1 }}
  data={workoutExercises}
  onDragEnd={onDragEnd}
  renderItem={renderItem}
  keyExtractor={(item) => {
    if (Array.isArray(item)) {
      return item[0].id;
    } else {
      return item.id;
    }
  }}
/>

ReplacementExerciseList(横向替换项列表)

<Animated.FlatList
  data={items}
  ref={ref}
  // contentContainerStyle={{ flexGrow: 1 }}
  renderItem={({ item, index }) => (
    <WorkoutExercisesListItem
      drag={drag}
      {...item}
      index={index}
      displaySetFinishedHeaderIcon={displaySetFinishedHeaderIcon}
      isReplacementExercise={true}
      computeHeight={computeListHeight}
    />
  )}
  scrollEnabled={false}
  // onViewableItemsChanged={handleVieweableItemsChanged}
  scrollEventThrottle={32}
  keyExtractor={(item) => item.id}
  horizontal={true}
  initialScrollIndex={activeIndex}
  showsHorizontalScrollIndicator={false}
  bounces={false}
  pagingEnabled={true}
/>

报错截图

报错截图


解决方案

1. 动态测量项高度+状态控制

提前测量所有替换项的高度,切换激活项时同步更新横向FlatList的高度:

  • 在ReplacementExercisesList组件内,添加状态存储每个项的高度和当前列表高度:
    import { LayoutChangeEvent } from 'react-native';
    
    const [itemHeights, setItemHeights] = useState<Record<number, number>>({});
    const [currentListHeight, setCurrentListHeight] = useState(0);
    
  • 给每个WorkoutExercisesListItem绑定onLayout事件,记录高度:
    const handleItemLayout = (index: number) => (event: LayoutChangeEvent) => {
      const { height } = event.nativeEvent.layout;
      if (!itemHeights[index]) {
        setItemHeights(prev => ({ ...prev, [index]: height }));
        // 初始激活项的高度直接设为列表高度
        if (index === activeIndex) setCurrentListHeight(height);
      }
    };
    
    // 在renderItem中使用
    <WorkoutExercisesListItem
      ...
      onLayout={handleItemLayout(index)}
    />
    
  • 监听激活索引变化,更新列表高度:
    useEffect(() => {
      if (itemHeights[activeIndex]) {
        setCurrentListHeight(itemHeights[activeIndex]);
      }
    }, [activeIndex, itemHeights]);
    
  • 给横向FlatList设置动态高度:
    <Animated.FlatList
      style={{ height: currentListHeight }}
      ...
    />
    

2. 避免布局循环报错

报错根源是同步修改高度触发的布局循环,解决关键点:

  • 不要在computeHeight这类同步方法里修改状态,改用onLayout异步记录高度。
  • 确保高度更新仅在测量完成后触发,避免重复触发重绘。

3. 优化布局配置

  • 移除横向FlatList父容器的flex:1设置,让列表高度由动态设置的currentListHeight决定。
  • 保持横向FlatList的contentContainerStyle不要设置flexGrow:1,避免自动拉伸导致高度异常。

内容的提问来源于stack exchange,提问作者maxi hraschan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:27:54