Grille de ListView en natif de React

je suis en train de construire une application simple dans React Native qui récupère les annonces d'une source distante JSON et les affiche à l'écran.

jusqu'à présent, en utilisant l'excellent exemple ici, j'ai réussi à obtenir les résultats à afficher en utilisant les composants ListView dans les lignes (i.e. 1 Résultat par ligne, voir screenshot). J'ai besoin que les résultats s'affichent dans une grille, c'est-à-dire de 3 à 6 éléments par rangée, selon la taille et l'orientation de l'écran.

quoi est la meilleure façon d'obtenir ces résultats dans une grille? Puis-je utiliser ListView pour cela, ou est-ce seulement pour un résultat par ligne? J'ai essayé de jouer avec les styles de flexbox, mais puisque React ne semble pas accepter % values et ListView n'accepte pas les styles, Je n'ai pas encore eu de succès.

This is how my listings are displaying at the moment - one per row.

56
demandé sur Mateo 2015-04-01 18:03:19

8 réponses

vous devez utiliser une combinaison de flexbox , et la connaissance que ListView enveloppe ScrollView et prend ainsi sur ses propriétés. Avec cela à l'esprit, vous pouvez utiliser l'hélice contentContainerStyle de ScrollView pour le style des articles.

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>}
        />
      );
    }
});

juste un ListView avec des données fictives. Notez l'utilisation de contentContainerStyle . Voici l'objet style:

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

nous disons au conteneur que nous voulons des articles dans une rangée d'emballage, et le la largeur de chaque objet enfant.

Screenshot

117
répondu Colin Ramsay 2015-04-01 16:10:24

j'ajoute ceci comme réponse parce que les commentaires de débordement sont cachés sous la réponse de Colin Ramsay: à partir de React Native 0.28, vous avez aussi besoin de alignItems: 'flex-start', dans le style listview ou le flexWrap ne fonctionnera pas. Merci à Kerumen sur codedump.io pour ça. So,

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

...avec le reste comme dans la réponse de Colin.

35
répondu kwishnu 2016-10-04 04:18:31

ListView est maintenant déprécié et vous devez utiliser FlatList à la place. FlatList a un prop appelé numColumns qui est exactement ce que nous voulons créer une grille scrollable.

par exemple:

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

Ce blog post fait un bon travail en expliquant les nouvelles fonctionnalités de FlatList.

Note: pour une raison quelconque, vous devez utiliser keyExtractor sur la FlatList au lieu de l'hélice typique key sur chaque élément. Sinon, vous recevrez un avertissement. Basic FlatList code says Warning-React Native

22
répondu Tim Perkins 2018-05-28 18:07:24

j'ai eu le même problème et j'ai écrit un composant qui résout ce problème, vous pouvez le trouver ici: https://github.com/pavlelekic/react-native-gridview

en outre, une autre chose que ce composant fait est qu'il s'assure que la largeur des articles est un nombre entier, de sorte que les bordures des articles n'ont pas antialiasing, ils sont clairs et croquants.

7
répondu Pavle Lekic 2017-02-07 21:19:45

suivez la réponse de Colin Ramsay. Et si vous voulez la moitié de la largeur pour chaque élément, essayez de cette façon.

...
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,
  },
});
5
répondu Yi Feng Xie 2017-01-21 18:26:27

utilisez FlatList au lieu de Listview dans react-native. il offre plus de fonctions à valeur ajoutée et de meilleures performances. vérifier l'exemple ici

2
répondu Moorthy 2017-12-11 21:19:58

vous pouvez utiliser FlatList et set numColumns pour obtenir le résultat qui est le même avec grid

1
répondu nguyencse 2017-11-04 07:47:14

cochez l'exemple suivant en utilisant FlatList composante de React Native pour supporter le défilement infini avec une excellente performance:

//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>
  )
}    

l'exemple ressemble à

enter image description here

meilleures salutations, Nicholls

0
répondu jdnichollsc 2018-02-23 21:48:30