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

React Native中BottomSheetModal内FlatList无法滚动问题求助

React Native BottomSheetModal内FlatList无法滚动问题

问题描述

在React Native应用中,将FlatList放入BottomSheetModal实现可选列表项时,FlatList能正常渲染条目,但当条目数量超出屏幕范围时,滚动功能完全失效,无法查看全部内容。

相关代码

BottomSheetModal使用代码

<BottomSheetModalProvider>
      <Container>
        <Header title="Home" showDrawerButton />
        <View style={{ padding: 20, flex: 1 }}>
          <CardButton title="Nova venda" onPress={handleSaleModal} />
        </View>
        <KeyboardAvoidingView
          behavior={Platform.OS === "ios" ? "padding" : "height"}
          style={{ flex: 1 }}
        >
          <BottomSheetModal
            ref={bottomSheetModalRef}
            index={1}
            snapPoints={snapPoints}
            backgroundStyle={{
              borderRadius: 24,
              backgroundColor: COLORS.GRAY_700,
            }}
            handleIndicatorStyle={{ backgroundColor: COLORS.BRAND_LIGHT }}
            backdropComponent={renderBackdrop}
          >
            <ContainerBottomSheet>
              <Highlight title="Nova venda" subtitle="" />
              <View style={{ flex: 1 }}>
                <CustomSelect
                  data={dataDropdownEmps}
                  onSelect={handleSelect}
                  showSearch
                />
              </View>
              <Button title="Iniciar" />
            </ContainerBottomSheet>
          </BottomSheetModal>
        </KeyboardAvoidingView>
      </Container>
    </BottomSheetModalProvider>

CustomSelect组件代码

import { CaretDown, CaretUp } from "phosphor-react-native";
import React, { useState } from "react";
import {
  FlatList,
  Text,
  TextInput,
  TouchableOpacity,
  View,
} from "react-native";
import { useTheme } from "styled-components/native";
import { ButtonSelect, ButtonSelectText, Container } from "./styles";

interface CustomSelectProps {
  data: SelectItem[];
  onSelect: (item: SelectItem | null) => void;
  showSearch?: boolean;
}

interface SelectItem {
  value: string;
  label: string;
}

export function CustomSelect({
  data,
  onSelect,
  showSearch = false,
}: CustomSelectProps) {
  const { COLORS } = useTheme();
  const [search, setSearch] = useState("");
  const [selectedItem, setSelectedItem] = useState<SelectItem | null>(null);
  const [isSearchClicked, setIsSearchClicked] = useState(false);

  const handleSelectItem = (item: SelectItem) => {
    setSelectedItem(item);
    onSelect(item);
    setIsSearchClicked(false);
  };

  const filteredData = data.filter((item) =>
    item.label.toLowerCase().includes(search.toLowerCase())
  );

  return (
    <Container>
      <ButtonSelect
        onPress={() => setIsSearchClicked(!isSearchClicked)}
        activeOpacity={0.7}
      >
        <ButtonSelectText>
          {selectedItem ? selectedItem.label : "Selecione um item"}
        </ButtonSelectText>
        {isSearchClicked ? (
          <CaretUp size={22} color={COLORS.WHITE} />
        ) : (
          <CaretDown size={22} color={COLORS.WHITE} />
        )}
      </ButtonSelect>
      {isSearchClicked && (
        <View
          style={{
            width: "100%",
            borderRadius: 6,
            marginTop: 10,
            gap: 10,
            backgroundColor: "white",
            elevation: 6,
          }}
        >
          {showSearch && (
            <TextInput
              placeholder="Search..."
              style={{
                width: "90%",
                height: 54,
                borderWidth: 0.5,
                borderColor: "#8e8e8e",
                borderRadius: 6,
                alignSelf: "center",
                marginTop: 10,
                paddingHorizontal: 10,
              }}
              value={search}
              onChangeText={(text) => setSearch(text)}
            />
          )}
          <FlatList
            data={filteredData}
            renderItem={({ item }) => (
              <TouchableOpacity
                onPress={() => handleSelectItem(item)}
                style={[
                  {
                    width: "100%",
                    paddingHorizontal: 10,
                    height: 54,
                    borderBottomWidth: 0.2,
                    borderBottomColor: "#8e8e8e",
                    alignSelf: "center",
                    justifyContent: "center",
                  },
                  // selectedItem?.value === item.value && styles.selectedItem,
                ]}
              >
                <Text>{item.label}</Text>
              </TouchableOpacity>
            )}
            keyExtractor={(item) => item.value}
            contentContainerStyle={[{ paddingBottom: 40, maxHeight: 200 }]}
          />
        </View>
      )}
    </Container>
  );
}

已尝试操作

  • 检查外层组件是否存在滚动阻塞,未发现异常
  • 为FlatList设置maxHeight属性,问题未解决

排查方向与修复方案

1. 开启嵌套滚动支持(Android)

Android中嵌套滚动容器内的FlatList需要显式开启nestedScrollEnabled属性才能正常响应滚动事件,修改FlatList配置:

<FlatList
  data={filteredData}
  renderItem={({ item }) => (...)}
  keyExtractor={(item) => item.value}
  contentContainerStyle={[{ paddingBottom: 40 }]}
  maxHeight={200}
  nestedScrollEnabled={true}
/>

2. 正确约束外层容器高度

给包裹FlatList的外层View设置明确的高度限制,确保FlatList有可滚动的空间:

{isSearchClicked && (
  <View
    style={{
      width: "100%",
      borderRadius: 6,
      marginTop: 10,
      gap: 10,
      backgroundColor: "white",
      elevation: 6,
      maxHeight: 250, // 留出搜索框空间的高度限制
    }}
  >
    {/* 搜索框组件 */}
    <FlatList
      data={filteredData}
      renderItem={({ item }) => (...)}
      keyExtractor={(item) => item.value}
      contentContainerStyle={[{ paddingBottom: 40 }]}
    />
  </View>
)}

3. 使用BottomSheet专属FlatList组件

若使用@gorhom/bottom-sheet库,推荐使用官方提供的BottomSheetFlatList,它会自动处理BottomSheet内部的滚动冲突:

// 导入组件
import { BottomSheetFlatList } from "@gorhom/bottom-sheet";

// 替换原有FlatList
<BottomSheetFlatList
  data={filteredData}
  renderItem={({ item }) => (...)}
  keyExtractor={(item) => item.value}
  contentContainerStyle={[{ paddingBottom: 40 }]}
  maxHeight={200}
/>

4. 调整KeyboardAvoidingView布局

外层KeyboardAvoidingView可能干扰BottomSheet的布局计算,尝试将其移至Modal内部或修改behavior属性:

<BottomSheetModal
  // ...其他属性
>
  <KeyboardAvoidingView
    behavior={Platform.OS === "ios" ? "padding" : "padding"}
    style={{ flex: 1 }}
  >
    <ContainerBottomSheet>
      {/* 原有内容 */}
    </ContainerBottomSheet>
  </KeyboardAvoidingView>
</BottomSheetModal>

内容的提问来源于stack exchange,提问作者Gustavo Rezin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 22:24:55