Je construis une application simple dans React Native qui récupère les listes à partir d'une source JSON distante et les affiche à l'écran.
Jusqu'ici, en utilisant l'excellent exemple ici, j'ai réussi à faire afficher les résultats en utilisant les composants ListView en lignes (c'est-à-dire 1 résultat par ligne, voir la capture d'écran). J'ai besoin que les résultats s'affichent dans une grille, c'est-à-dire 3 à 6 éléments par ligne, en fonction de la taille et de l'orientation de l'écran.
Quel est le meilleur moyen d’obtenir ces résultats dans une grille? Puis-je utiliser ListView pour cela, ou est-ce seulement pour des résultats d'un rang par ligne? J'ai essayé de jouer avec les styles flexbox, mais comme React ne semble pas accepter les valeurs% et que ListView n'accepte pas les styles, je n'ai pas encore eu de succès.
Vous devez utiliser une combinaison de flexbox et la connaissance que ListView englobe ScrollView et prend ainsi ses propriétés. Dans cet esprit, vous pouvez utiliser la propriété contentContainerStyle
du ScrollView pour styliser les éléments.
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 une liste avec des données factices. Notez l'utilisation de contentContainerStyle
. Voici l'objet de 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 éléments dans une ligne d'habillage et définissons la largeur de chaque objet enfant.
J'ajoute ceci comme réponse car les commentaires de débordement sont cachés sous la réponse de Colin Ramsay: à partir de React Native 0.28, vous avez également besoin de alignItems: 'flex-start',
dans le style de la liste ou le flexWrap ne fonctionnera pas. Merci à Kerumen sur codedump.io pour cela. Alors,
var styles = StyleSheet.create({
list: {
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'flex-start',
},
... avec le reste comme dans la réponse de Colin.
ListView est maintenant obsolète et vous devez utiliser FlatList à la place. FlatList a un accessoire appelé numColumns
qui correspond exactement à ce que nous voulons créer une grille défilable.
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} />
);
}
Ce blog billet explique très bien les nouvelles fonctionnalités de FlatList.
Remarque: pour une raison quelconque, vous devez utiliser keyExtractor
sur la FlatList au lieu du prop key
typique de chaque élément. Sinon, vous recevrez un avertissement. Le code de base FlatList renvoie Warning - React Native
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, ce composant permet également de s'assurer que la largeur des éléments est un nombre entier, de sorte que les bordures des éléments ne comportent pas d'antialiasing, elles sont claires et nettes.
Suivez la réponse de Colin Ramsay. Et si vous voulez une demi-largeur pour chaque article, 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,
},
});
utilisez FlatList au lieu de Listview dans react-native. il a plus de valeur ajoutée et de meilleures performances. consultez l'exemple ici
Vous pouvez utiliser FlatList et définir numColumns pour obtenir le résultat identique à celui de grid
Consultez l'exemple suivant en utilisant le composant FlatList de React Native pour prendre en charge le défilement infini avec d'excellentes performances:
//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 à
Cordialement, Nicholls