Сетка ListView в React Native


Я создаю простое приложение в React Native, которое извлекает списки из удаленного источника JSON и отображает их на экране.

до сих пор, используя прекрасные пример здесь мне удалось получить результаты для отображения с помощью компонентов ListView в строках (т. е. 1 результат на строку, см. скриншот). Мне нужно, чтобы результаты отображались в сетке, т. е. от 3 до 6 элементов в строке, в зависимости от размера экрана и ориентации.

Что является лучшим способом, чтобы получить эти результаты в сетку? Могу ли я использовать ListView для этого, или это только для результатов по одной строке? Я пробовал играть со стилями flexbox, но, поскольку React, похоже, не принимает значения%, а ListView не принимает стили, у меня еще не было успеха.

8 56

8 ответов:

вы должны использовать комбинацию flexbox, и знание, что ListView обертывает ScrollView и поэтому принимает его свойства. Имея это в виду, вы можете использовать ScrollView contentContainerStyle опора для стиля элементы.

var TestCmp = React.createClass({
    getInitialState: function() {
      var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
      var data = Array.apply(null, {length: 20}).map(Number.call, Number);
      return {
        dataSource: ds.cloneWithRows(data),
      };
    },

    render: function() {
      return (
        <ListView contentContainerStyle={styles.list}
          dataSource={this.state.dataSource}
          renderRow={(rowData) => <Text style={styles.item}>{rowData}</Text>}
        />
      );
    }
});

просто ListView с некоторыми фиктивными данными. Обратите внимание на использование contentContainerStyle. Вот объект стиля:

var styles = StyleSheet.create({
    list: {
        flexDirection: 'row',
        flexWrap: 'wrap'
    },
    item: {
        backgroundColor: 'red',
        margin: 3,
        width: 100
    }
});

мы говорим контейнеру, что хотим элементы в строке упаковки, и мы устанавливаем ширину каждого ребенка объект.

Screenshot

Я добавляю это в качестве ответа, потому что комментарии переполнения скрыты под ответом Колина Рамсея: начиная с React Native 0.28, вам также нужно alignItems: 'flex-start', в стиле listview или flexWrap не будет работать. Благодаря Kerumen on codedump.io за это. Итак,

var styles = StyleSheet.create({
list: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    alignItems: 'flex-start',
},

...с остальными, как в ответе Колина.

ListView теперь устаревший и вы должны использовать FlatList. FlatList имеет опору под названием numColumns это именно то, что мы хотим создать сетку.

например:

const data = [
  {id: 'a', value: 'A'},
  {id: 'b', value: 'B'},
  {id: 'c', value: 'C'},
  {id: 'd', value: 'D'},
  {id: 'e', value: 'E'},
  {id: 'f', value: 'F'},
];
const numColumns = 3;
const size = Dimensions.get('window').width/numColumns;
const styles = StyleSheet.create({
  itemContainer: {
    width: size,
    height: size,
  },
  item: {
    flex: 1,
    margin: 3,
    backgroundColor: 'lightblue',
  }
});

function Grid(props) {
  return (
    <FlatList
      data={data}
      renderItem={({item}) => (
        <View style={styles.itemContainer}>
          <Text style={styles.item}>{item.value}</Text>
        </View>
      )}
      keyExtractor={item => item.id}
      numColumns={numColumns} />
  );
}

enter image description here

этой блоге делает хорошую работу, объясняя новые возможности FlatList.

примечание: по какой-то причине вы должны использовать keyExtractor на FlatList вместо типичного key опора на каждом элементе. В противном случае вы получите предупреждение. основной FlatList код выдает предупреждение-React Native

У меня была та же проблема, и я написал компонент, который решает эту проблему, вы можете найти его здесь:https://github.com/pavlelekic/react-native-gridview

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

следуйте ответу Колина Рамзи. И если вы хотите половину ширины для каждого элемента, попробуйте этот способ.

...
import { Dimensions } from 'react-native'; 
const { width, height } = Dimensions.get('window');
const gutter = 0; // You can add gutter if you want
...


const styles = StyleSheet.create({
  item: {
    width: (width - gutter * 3)/2,
    marginBottom: gutter,
    flexDirection: 'column',
    alignSelf: 'flex-start',
    backgroundColor: '#ff0000',
  },
  list: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    flexWrap: 'wrap',
    paddingHorizontal: gutter,
  },
});

используйте FlatList вместо Listview в react-native. он имеет более высокую добавленную стоимость и лучшую производительность. оформить заказ

вы можете использовать FlatList и установить numColumns для получения результата, который совпадает с grid

Проверьте следующий пример с помощью FlatList компонент Реагировать Уроженца для поддержки бесконечной прокрутки с отличной производительностью:

//Resize the grid
onLayout = (event) => { 
  const {width} = event.nativeEvent.layout;
  const itemWidth = 150
  const numColumns = Math.floor(width/itemWidth)
  this.setState({ numColumns: numColumns })
}

render() {
  return (
    <Content 
     contentContainerStyle={{flex:1, alignItems: 'center'}}
     onLayout={this.onLayout}>
       <FlatList
        data={this.state.products}
        keyExtractor={(item, index) => index}
        key={this.state.numColumns}
        numColumns={this.state.numColumns}
        renderItem={({item}) => 
          <ListThumb //Custom component, it's only an example.
           navigation={navigation}
           brand={item.brand}
           price={item.price}
           imageSource={item.image_link}/>
        }
     />
   </Content>
  )
}    

пример выглядит так:

enter image description here

С наилучшими пожеланиями, Николс