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

React Native中FlatList内嵌Native Base Modal黑屏闪烁问题求助

问题原因及解决方案

核心原因

  • Modal重复渲染冲突:你将Native Base的Modal组件放在了FlatList的renderItem方法内部,这会导致FlatList的每一条数据项都生成一个独立的Modal实例。当modalVisible设为true时,所有列表项的Modal会同时尝试显示,多个Modal叠加触发渲染冲突,表现为背景变黑、闪烁。
  • 动画层级冲突:FlatList使用了Native驱动的滚动动画(useNativeDriver: true),Modal的显示逻辑与这个动画系统的渲染层级相互干扰,进一步加重了闪烁问题。

修复步骤

  1. 将Modal移到FlatList外部:确保全局只有一个Modal实例,避免多实例同时触发。
  2. 优化状态控制:保持modalVisible状态仅控制唯一的Modal,避免不必要的重复渲染。
  3. 调整Modal配置:可检查Native Base Modal的backdrop属性,设置合适的背景透明度与动画,减少和滚动动画的冲突。

修改后的代码示例

export function Prospecction() {
  const scrollY = React.useRef(new Animated.Value(0)).current;
  const navigation = useNavigation();

  const [modalVisible, setModalVisible] = React.useState(false);

  const initialRef = React.useRef(null);
  const finalRef = React.useRef(null);

  return (
    <View style={{ flex: 1, backgroundColor: "#fff" }}>
      <Animated.FlatList
        data={DATA}
        onScroll={Animated.event(
          [{ nativeEvent: { contentOffset: { y: scrollY } } }],
          { useNativeDriver: true }
        )}
        keyExtractor={(item) => item.key}
        contentContainerStyle={{
          padding: SPACING,
          paddingTop: StatusBar.currentHeight || 42,
        }}
        renderItem={({ item, index }) => {
          const inputRange = [
            -1,
            0,
            ITEM_SIZE * index,
            ITEM_SIZE * (index + 2),
          ];
          const opacityInputRange = [
            -1,
            0,
            ITEM_SIZE * index,
            ITEM_SIZE * (index + 1),
          ];

          const scale = scrollY.interpolate({
            inputRange,
            outputRange: [1, 1, 1, 0],
          });

          const opacity = scrollY.interpolate({
            inputRange: opacityInputRange,
            outputRange: [1, 1, 1, 0],
          });
          return (
            <Animated.View
              style={{
                elevation: 10,
                flexDirection: "row",
                padding: SPACING,
                marginBottom: SPACING,
                backgroundColor: "#fff",
                borderRadius: 12,
              }}
            >
              <View style={{ flexDirection: "column" }}>
                <View style={{ flexDirection: "row" }}>
                  <Image
                    source={{ uri: item.image }}
                    alt="Alternate Text"
                    size="xl"
                    style={{
                      width: AVATAR_SIZE,
                      height: AVATAR_SIZE,
                      borderRadius: AVATAR_SIZE,
                      marginRight: SPACING / 2,
                    }}
                  />

                  <View style={{ flexDirection: "column" }}>
                    <Text
                      style={{
                        fontSize: 22,
                        fontWeight: "700",
                        textAlign: "left",
                        marginTop: SPACING - 4,
                      }}
                    >
                      {item.name}
                    </Text>
                    <Text
                      style={{
                        fontSize: 13,
                        opacity: 0.5,
                        fontWeight: "700",
                        textAlign: "left",
                      }}
                    >
                      {item.adate}
                    </Text>
                  </View>
                </View>

                <View
                  style={{ marginTop: SPACING - 5, flexDirection: "column" }}
                >
                  <Text
                    style={{
                      fontSize: 16,
                      opacity: 0.7,
                      textAlign: "left",
                      alignSelf: "flex-start",
                    }}
                  >
                    <Text style={{ fontWeight: "bold" }}>Interno:</Text>{" "}
                    {item.intern}{" "}
                  </Text>
                  <Text
                    style={{
                      fontSize: 16,
                      opacity: 0.7,
                      textAlign: "left",
                      alignSelf: "flex-start",
                    }}
                  >
                    <Text style={{ fontWeight: "bold" }}>Externo:</Text>{" "}
                    {item.extern}
                  </Text>
                </View>
              </View>
              <View
                style={{
                  marginTop: SPACING - 5,
                  flexDirection: "column",
                  marginLeft: 80,
                }}
              >
                <Text
                  style={{
                    fontSize: 14,
                    fontWeight: "700",
                    textAlign: "right",
                    color: "#7B61FF",
                    alignContent: "space-between",
                  }}
                ></Text>
              </View>
              <View
                style={{
                  position: "absolute",
                  marginLeft: "5%",
                  marginTop: "5%",
                  right: 0,
                  flexWrap: "wrap",
                }}
              >
                <Text
                  style={{
                    fontSize: 14,
                    fontWeight: "700",
                    textAlign: "right",
                    color: "#7B61FF",
                  }}
                >
                  {item.status}
                </Text>
              </View>

              <View
                style={{
                  marginTop: SPACING - 5,
                  flexGrow: 1,
                  flexDirection: "column",
                  marginTop: "auto",
                  flexWrap: "wrap-reverse",
                }}
              >
                <IconButton
                  icon="card-account-details-outline"
                  iconColor={MD3Colors.secondary30}
                  size={30}
                  onPress={() => navigation.navigate("ClientInfo")}
                />
              </View>
            </Animated.View>
          );
        }}
      ></Animated.FlatList>

      {/* 全局唯一的Modal实例,移到FlatList外部 */}
      <Modal
        isOpen={modalVisible}
        onClose={() => setModalVisible(false)}
        initialFocusRef={initialRef}
        finalFocusRef={finalRef}
      >
        <Modal.Content>
          <Modal.CloseButton />
          <Modal.Header>Adicionar comentário</Modal.Header>
          <Modal.Body>
            <FormControl>
              <FormControl.Label>
                <Text style={{ fontSize: 18, fontWeight: "bold" }}>
                  Comentário
                </Text>
              </FormControl.Label>
            </FormControl>
            <FormControl mt="3">
              <View style={{ padding: 1 }}>
                <TextInput
                  style={{
                    flex: 1,
                    borderColor: "white",
                    borderRadius: 5,
                    borderWidth: 1,
                    backgroundColor: "#E6E7ED",
                    textAlign: "left",
                  }}
                  placeholder="Digite seu comentário aqui"
                  autoFocus={true}
                  numberOfLines={10}
                  multiline
                ></TextInput>
              </View>
            </FormControl>
          </Modal.Body>
          <Modal.Footer justifyContent="center" alignItems="center">
            <Button.Group
              justifyContent="center"
              alignItems="center"
            >
              <Button
                onPress={() => {
                  setModalVisible(false);
                }}
                justifyContent="center"
                alignItems="center"
                rounded={15}
                height={55}
                width="80%"
                bgColor="#250D8A"
                _pressed={{ bgColor: "#4530a7" }}
              >
                Adicionar
              </Button>
            </Button.Group>
          </Modal.Footer>
        </Modal.Content>
      </Modal>

      <IconButton
        style={{
          position: "absolute",
          bottom: 0,
          right: 0,
        }}
        icon="plus-circle-outline"
        iconColor={MD3Colors.secondary30}
        size={30}
        onPress={() => {
          setModalVisible(!modalVisible);
        }}
      />
    </View>
  );
}

额外注意点

  • 若需针对不同列表项展示Modal内容,可通过状态存储当前选中项,在Modal中根据该状态渲染对应内容。
  • 检查Native Base版本,部分旧版本Modal与Animated组件配合时存在渲染bug,必要时升级至最新稳定版。

内容的提问来源于stack exchange,提问作者Carry Flag

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 04:45:30