Строка Flatlist с элементами разного размера

Я использую плоский список для создания сетки элементов, содержащих изображения, видео, блоги и аудио. В плоском списке есть две колонки. Я добавил кнопку для добавления фиктивных сообщений в плоский список. Проблема в высоте предметов. Когда я добавляю блог в плоский список, в нем есть текст, изображения и элемент рядом с ним. то есть изображение или видео также получают высоту элемента блога. Можно ли задать переменную высоту для каждого элемента в строке. При добавлении блога в плоский список элемент видео также имеет высоту, соответствующую элементу блога.

снимок экрана с проблемой


person Paras Watts    schedule 23.08.2017    source источник


Ответы (4)


Согласно официальному документу, когда в плоском списке несколько столбцов, Items should all be the same height - masonry layouts are not supported.

Но я думаю, вы можете попробовать добавить оболочку View для каждого элемента столбца, чтобы избежать этого правила. height плоского списка будет установлено на обертке, высота вашего элемента все еще может быть настроена вами.

person Harlan    schedule 23.08.2017
comment
Я постараюсь вернуться к вам - person Paras Watts; 23.08.2017
comment
Привет, спасибо за ваш ответ, я могу изменить рост. Но теперь есть другая проблема: под элементом есть место, если элемент рядом с ним имеет большую высоту. - person Paras Watts; 24.08.2017
comment
Это не может быть исправлено из-за правила, которое я только что упомянул. Я думаю, вам стоит попробовать какую-нибудь стороннюю библиотеку. эта библиотека может удовлетворить ваш запрос. реагировать-native-masonry - person Harlan; 24.08.2017
comment
Я думаю, что эта библиотека работает только с изображениями. У меня есть различные типы компонентов: изображение, видео, блог, аудио. - person Paras Watts; 24.08.2017

Я использую эту библиотеку для создания масонского списка. https://github.com/AppAndFlow/react-native-masonry-list .Он работает так, как ожидалось.

person Paras Watts    schedule 19.03.2018

Вы можете попробовать использовать ScrollView внутри FlatList с одним элементом.

import React, {useEffect, useState} from 'react';
import {
  View,
  FlatList,
  Image,
  ScrollView,
  Text,
  Dimensions,
} from 'react-native';
const {height, width} = Dimensions.get('window');
const DATA = [
  {
    url:
      'https://images.pexels.com/photos/4689912/pexels-photo-4689912.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 400,
  },
  {
    url:
      'https://images.pexels.com/photos/2736843/pexels-photo-2736843.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 100,
  },
  {
    url:
      'https://images.pexels.com/photos/4407291/pexels-photo-4407291.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 100,
  },
  {
    url:
      'https://images.pexels.com/photos/4553021/pexels-photo-4553021.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/4689912/pexels-photo-4689912.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/2736843/pexels-photo-2736843.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/4407291/pexels-photo-4407291.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/4553021/pexels-photo-4553021.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/4689912/pexels-photo-4689912.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/2736843/pexels-photo-2736843.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/4407291/pexels-photo-4407291.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/4553021/pexels-photo-4553021.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/4689912/pexels-photo-4689912.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/2736843/pexels-photo-2736843.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/4407291/pexels-photo-4407291.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
  {
    url:
      'https://images.pexels.com/photos/4553021/pexels-photo-4553021.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500',
    height: 200,
  },
];
const W = width / 2 - 10 - 4;
const Item = ({url, height}) => {
  const [dims, setDims] = useState({height: 0, width: 0});
  useEffect(() => {
    setDims({height: Math.random() * 1000});
    // Image.getSize(url, ([h, w]) => {
    //   console.log('<<h, w', h, w);
    // });
  }, [url]);
  return (
    <View
      style={{
        width: W,
        height: dims.height,
        margin: 5,
        padding: 1,
        backgroundColor: 'red',
      }}>
      {/* <Text>{JSON.stringify(dims, null, 2)}</Text> */}
      <Image
        source={{uri: url}}
        style={{
          height: '100%',
          width: '100%',
        }}
      />
    </View>
  );
};
export default () => {
  const [data, setData] = useState([...DATA]);
  // let prevY = React.useRef(0).current;
  // const offsetY = new Animated.Value(0);
  return (
    <View
      style={{
        flex: 1,
        backgroundColor: '#DDDDDD',
        flexDirection: 'row',
      }}>
      <FlatList
        data={[1]}
        onEndReached={() => {
          setData((prev) => {
            return [...prev, ...DATA];
          });
          console.log('<<EENDDD');
        }}
        renderItem={() => {
          return (
            <ScrollView
              contentContainerStyle={{
                flexDirection: 'row',
                backgroundColor: 'blue',
                marginVertical: 10,
              }}>
              <View>
                {data.map((item) => {
                  return <Item {...item} />;
                })}
              </View>
              <View>
                {data.map((item) => {
                  return <Item {...item} />;
                })}
              </View>
            </ScrollView>
          );
        }}
      />
    </View>
  );
};
person Lokesh Dangi    schedule 12.10.2020

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

Реализация немного сложна — нам нужно применить отрицательное поле в свойстве 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