Плоский список превышает свой контейнер своим содержимым: Как создать плоский список с фиксированной высотой

#javascript #react-native #react-native-flatlist #flatlist

Вопрос:

У меня есть <FlatList /> . Внутри этого <FlatList /> у меня есть еще <FlatList /> одно . Вложенное <FlatList /> дает мне какое-то странное поведение. Он превышает пределы своего контейнера. Как вы можете видеть, Флаги идут над yellow полем, которые представляют границы <FlatList /> .

Вот вам закуска https://snack.expo.dev/@stophfacee/nested-flatlist что воспроизводит проблему.

Пожалуйста, обратите внимание: анимация (при касании hotpink прямоугольника) работает неправильно. Я не уверен, почему. Однако я все равно включил его, потому что не уверен, что в этом может быть проблема.

Комментарии:

1. overflow: hidden Дает ли добавление styles.flagsContainer вам желаемое поведение?

2. @Dan, который ограничивает его yellow контейнером, но делает его разворачиваемым.

3. Ну, я думаю, вам следует проверить recyclerlistview

4. Я предпочитаю использовать SectionList для таких вещей.

5. Что делать, если вы измените внешний плоский список на вид прокрутки, содержащий все карты (включая плоский список)?

Ответ №1:

Возможно, это тот результат, которого вы хотели. Пожалуйста, проверьте это один раз!

 import React, { useState } from 'react';
import {
  View,
  StyleSheet,
  Animated,
  Dimensions,
  TouchableOpacity,
  Text,
  ScrollView,
} from 'react-native';
import Constants from 'expo-constants';
import CountryFlag from 'react-native-country-flag';
import { FlatList } from 'react-native-gesture-handler';

export default function App() {
  const _renderFlag = (country) => {
    return (
      <TouchableOpacity onPress={() => console.log('Flag touched')}>
        <CountryFlag
          isoCode={'NZ'}
          size={50}
          style={{ alignSelf: 'flex-end' }}
        />
      </TouchableOpacity>
    );
  };

  const _createCard = (card, index) => {
    return (
      <View style={styles.card} key={index}>
        <TouchableOpacity
          style={styles.touchable}
          onPress={() => console.log('toggle')}>
          <Text>{card}</Text>
        </TouchableOpacity>
        <View style={{ height: 200 }}>
          <FlatList
            nestedScrollEnabled={true}
            style={{ marginTop: 20, backgroundColor: 'yellow' }}
            columnWrapperStyle={{
              justifyContent: 'space-around',
            }}
            ItemSeparatorComponent={() => <View style={{ margin: 10 }}/>}
            numColumns={3}
            data={[
              1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
            ]}
            renderItem={_renderFlag}
            keyExtractor={(item, index) => index.toString()}
            getItemLayout={(data, index) => ({
              length: 50,
              offset: 50 * index,
              index,
            })}
          />
        </View>
      </View>
    );
  };

  return (
    <View style={{ flex: 1 }}>
      <FlatList
        style={{ margin: 20 }}
        data={['a', 'b', 'c']}
        keyExtractor={(item, index) => index.toString()}
        renderItem={({ item, index }) => _createCard(item, index)}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    borderColor: 'red',
    borderWidth: 2,
    padding: 8,
    marginBottom: 15,
  },
  touchable: {
    backgroundColor: 'hotpink',
    height: 50,
    width: '100%',
    justifyContent: 'center',
    alignItems: 'center',
  },
});
 

Рабочий Пример

Комментарии:

1. Это не решение проблемы. Когда вы вкладываете a <FlatList /> в a <ScrollView /> , вы получаете следующее предупреждение: виртуализированные списки никогда не должны быть вложены в простые представления прокрутки с той же ориентацией — вместо этого используйте другой контейнер с поддержкой VirtualizeList.

2. Я обновил ответ. Немного покопавшись, я обнаружил, что для включения прокрутки вложенного плоского списка мы должны импортировать плоский список из обработчика жестов react-native.

Ответ №2:

Я не очень хорошо разбираюсь в react native, и я действительно не вижу вашей проблемы, однако вы упомянули, что она проходит через контейнер. Я взглянул на ваш код и знаю, что в обычном css/web ваш стиль не будет работать.

У вас есть <FlatList , и вы придали ему стиль style={styles.container} . Стиль этого контейнера таков:

 container: {
  paddingTop: 50,
  height: '100%',
  widht: '100%',
}
 

Там вы указываете, чтобы контейнер был height: 100% , а затем вы также указываете, чтобы он имел заполнение 50. Это приведет к общей высоте 100% 50. Для того, чтобы исправить это, вы должны использовать height: calc(100% - 50) вместе с вашей прокладкой, тогда она идеально подойдет.

Я понятия не имею, является ли это вашей реальной проблемой, но я не вижу, как это будет работать, если только react native не делает какие-то странные вещи с дополнениями.

На самом деле вы также сделали это в нескольких местах на своей карте, которую вы использовали width: '90%' вместе с padding: 8 , так что эта карта переполнит свой контейнер 6. Там вам тоже нужно это сделать width: calc(100% - 16) .

Это станет еще более запутанным, если у вас есть borderWidth: 2 и у вас нет box-sizing: border-box , что приведет к тому, что он будет еще на 4 больше по ширине контейнера.

Вы должны быть осторожны с дополнительными дополнениями/границами/и т.д., Которые вы добавляете, когда указываете, что это 100% ширина/высота.

Ответ №3:

Принимая во внимание советы Дэна и Амерлики, это возможное использование SectionList , которое, по-видимому, решит вашу проблему:

Не забудьте импортировать SectionList из react-native !

  const sections = [
    { title: 'Section 1', data: ['a', 'b', 'c'].map((card, index) => _createCard(card, index)) },
    { title: 'Section 2', data: ['a', 'b', 'c'].map((card, index) => _createCard(card, index)) },
    { title: 'Section 3', data: ['a', 'b', 'c'].map((card, index) => _createCard(card, index)) },
  ];

  return (
    <SectionList
      initialNumToRender={2}
      contentContainerStyle={{ alignItems: 'center' }}
      style={styles.container}
      sections={sections}
      renderItem={(item) => {
        return item.item;
      }}
      renderSectionHeader={({ section: { title } }) => (
        <View style={{ backgroundColor: 'pink', width:200,  alignItems: 'center', justifyContent: 'center', height: 50 }}>
          <Text>{title}</Text>
        </View>
      )}
    />
  );