Два столбца в RN FlatList

Как я могу перечислить 2 столбца в React Native Flatlist, например:

введите описание изображения здесь


person doublemax    schedule 18.01.2018    source источник
comment
Вы пытаетесь создать макет с переменной высотой? Кроме того, что вы сделали, чтобы решить эту проблему? Есть и другие похожие вопросы с ответами, но я не могу сказать, в чем отличие, так как у вас очень мало деталей. См. Как спросить.   -  person Michael Cheng    schedule 19.01.2018
comment
макет с переменной высотой не имеет значения. numColumns создает сетку.   -  person doublemax    schedule 19.01.2018


Ответы (6)


Просто передайте свойство numColumns вашему компоненту FlatList.

person Eduardo Macêdo    schedule 19.01.2018
comment
Я тоже так думал, но когда я прочитал реквизит, я увидел следующее: Все элементы должны быть одинаковой высоты — макеты каменной кладки не поддерживаются. Похоже, что OP пытается использовать такой макет, так что это будет не работает, если нет какой-то хитрости со стилем, которую можно сделать. - person Michael Cheng; 19.01.2018
comment
@MichaelCheng Хотя пример изображения имеет разную высоту, в вопросе не упоминается, что для него потребуется разная высота, он просто спрашивает, как получить два столбца в компоненте FlatList. Я думаю, что автор вопроса не знает об этой опоре. - person Eduardo Macêdo; 19.01.2018
comment
Согласовано. Я отмечу и прокомментирую, чтобы попросить разъяснений. - person Michael Cheng; 19.01.2018
comment
numColumns создает сетку. - person doublemax; 19.01.2018
comment
Примечание для себя: создание внутренних элементов flex:1 заполнит ширину - person MonoThreaded; 07.12.2019

Вы можете сделать это одним из двух способов. Во-первых, прямой способ — создать 2 столбца FlatList с гибкой компоновкой и распределить данные между ними следующим образом:

Предполагая, что вы определили style и data

const style={
  container: {
    flex: 1,
    flexDirection: 'row',
    height: 400
  },
  column: {
    flex: 1,
    flexDirection: 'column'
  },
  row: {
    flexDirection: 'row'
  },
  item: {
    flex: 1
  }
}

const data = [
  { key: 'A' },
  { key: 'B' },
  { key: 'C' },
  { key: 'D' },
  { key: 'E' },
  { key: 'F' },
  { key: 'G' },
  { key: 'H' },
  { key: 'I' }
];

Вы можете это сделать

render() {
  //Split the data (however you want it)
  const column1Data = data.filter((item, i) => i%2 === 0);
  const column2Data = data.filter((item, i) => i%2 === 1);

  return (
    <View style={ style.container }>

      <View style={ style.column }>
        <Text>Column 1</Text>
        <FlatList
          data={ column1Data }
          renderItem={ ({ item }) => (
            <View style={ style.item }>
              <Text>{ item.key }</Text>
            </View>
          ) }
        />
      </View>

      <View style={ style.column }>
        <Text>Column 2</Text>
        <FlatList
          data={ column2Data }
          renderItem={ ({ item }) => (
            <View style={ style.item }>
              <Text>{ item.key }</Text>
            </View>
          ) }
        />
      </View>

    </View>
  );
}

Проблема заключается в том, что оба списка являются независимыми и будут плохо работать на мобильных устройствах. Лучшим способом было бы сгруппировать ваши данные и отобразить один столбец FlatList, чтобы ваш контент был унифицирован.

Во-первых, вам понадобится функция для группировки ваших данных в "строки" данных.

  //The key here is grouping the data to be in one row together
  const groupData = (items, groupLen) => {
    const groups = [];
    let i = 0;

    while (i < items.length) {
      groups.push(items.slice(i, i += groupLen));
    }

    return groups;
  };

Тогда сделайте это...

render() {
  const groupedItems = groupData(data, 2)

  return (
    <View style={ style.column }>

        <Text>Main Column</Text>
        <FlatList
          data={ groupedItems }
          renderItem={ ({ item }) => (
            <View style={ style.row }>
              {
                /* item is really the group of items in the row */
                item.map((singleItem, index ) => (
                  <Text style={ style.item }>{ singleItem.key }</Text>
                ))
              }
            </View>
          ) }
        />

    </View>
  );
}

Вам, вероятно, придется повозиться со стилем, чтобы получить его так, как вы хотите, но вы поняли идею :)

person Mohammed Siddeeq    schedule 18.01.2018
comment
FlatList не поддерживает элементы разной высоты, такие как вопрос ОП. - person N S; 02.04.2018

Мне потребовалось много времени, чтобы понять это, но на самом деле этого можно добиться без использования каких-либо внешних библиотек. Хитрость заключается в использовании отрицательной маржи.

Отрицательное поле будет применено к свойству VirtualizedList CellRendererComponent, чтобы заставить его правильно работать на Android.

JSX:

<View style={styles.container}>
      <FlatList
        style={styles.flatlist}
        data={data}
        keyExtractor={(item, index) => index.toString()}
        CellRendererComponent={({ children, item, ...props }) => {
            return (
                <View {...props} style={{ marginTop: item.marginTop }}>
                    {children}
                </View>
            )
        }}
        renderItem={({ item }) => {
            const { source: source1, height: height1, marginTop: marginTop1 } = item.image1;
            const { source: source2, height: height2, marginTop: marginTop2 } = item.image2;
            return (
                <View style={Style.viewRow}>
                    <Image source={source1} style={[styles.image, { height: height1, marginTop: marginTop1 }]} />
                    <Image source={source2} style={[styles.image, { height: height2, marginTop: marginTop2 }]} />
                </View>
            )
        }}
    />
</View>

Данные:

const source = { uri: 'https://placekitten.com/160/300' };

const data = [
    {
        marginTop: 0,
        image1: { source, height: 300, marginTop: 0 },
        image2: { source, height: 250, marginTop: 0 }
    },
    {
        marginTop: -50,
        image1: { source, height: 290, marginTop: 50 },
        image2: { source, height: 300, marginTop: 0 }
    },
    {
        marginTop: -40,
        image1: { source, height: 250, marginTop: 40 },
        image2: { source, height: 350, marginTop: 0 }
    }
];

Стили:

const styles = StyleSheet.create({
   container: {
      flex: 1
   },
   flatList: {
      width: '100%',
      height: '100%'
   },
   viewRow: {
      flexDirection: 'row'
   },
   image: {
      width: '50%',
      resizeMode: 'cover'
   }
});

Обратите внимание, что правильное расположение изображений в массиве зависит от вас — всегда размещайте более высокое изображение на более короткой стороне и обязательно вычисляйте разницу высот и отслеживайте ее. Веселиться.

person Dror Bar    schedule 15.03.2019

В react-native стандартным стилем является flexDirection: 'col', что означает расположение элементов сверху вниз. Чтобы изменить это (справа налево), вы должны установить стиль на flexDirection: 'row'.

<View style={{flexDirection: 'row'}}>
  <FlatList
    data={[{key: 'a'}, {key: 'b'}]}
    renderItem={({item}) => <Text>{item.key}</Text>}
  />
  <FlatList
    data={[{key: 'a'}, {key: 'b'}]}
    renderItem={({item}) => <Text>{item.key}</Text>}
  />
</View>
person Piu130    schedule 18.01.2018

Пройти numColumns

<FlatList 
 data={albums}
 renderItem={({item}) => <></>}
 numColumns={2}
/>
person Community    schedule 26.03.2019

вы можете попробовать с react-native-scroll-lazy вместо ScrollView. Раньше у меня были проблемы, подобные описанным выше, я решил их и написал библиотеку, чтобы поделиться с людьми, у которых такая же проблема.

person Tung Tran    schedule 14.08.2020
comment
Раньше, когда вы публиковали этот ответ на несколько вопросов, модератор удалял большинство из них, потому что, как правило, если идентичный ответ может решить несколько вопросов, вы должны пометить их как повторяющиеся и не публиковать один и тот же ответ, особенно , если вы публикуете ответы для продвижения своих собственных библиотека. - person David Buck; 14.08.2020