2015-04-01 29 views
50

Sto costruendo una semplice app in React Native che recupera gli elenchi da una sorgente JSON remota e li visualizza sullo schermo.Griglia di ListView in React Native

Finora, utilizzando l'eccellente example qui, sono riuscito a visualizzare i risultati utilizzando i componenti ListView in righe (ovvero 1 risultato per riga, vedere screenshot). Ho bisogno che i risultati vengano visualizzati in una griglia, cioè da 3 a 6 elementi per riga, a seconda delle dimensioni e dell'orientamento dello schermo.

Qual è il modo migliore per ottenere questi risultati in una griglia? Posso usare ListView per questo, o è solo per risultati a una riga? Ho provato a giocare con gli stili di Flexbox ma, dal momento che React non sembra accettare i valori% e ListView non accetta gli stili, non ho ancora avuto alcun successo.

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

risposta

104

è necessario utilizzare una combinazione di flexbox, e la consapevolezza che ListView avvolge ScrollView e così prende sulle sue proprietà. Con questo in mente è possibile utilizzare il puntello contentContainerStyle di ScrollView per modellare gli oggetti.

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

Solo un ListView con alcuni dati fittizi. Notare l'uso di contentContainerStyle. Ecco l'oggetto di stile:

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

Raccontiamo il contenitore che vogliamo articoli di fila avvolgimento e l'abbiamo impostato la larghezza di ogni oggetto figlio.

Screenshot

+0

Colin, grazie mille per questo. Ci proverò. – Mateo

+0

Questo è esattamente quello che stavo cercando per qualcosa che sto facendo! Grazie! –

+0

GRAZIE! Questo è esattamente quello che speravo, ma non pensavo esistesse. – rxb

33

che sto aggiungendo questo come una risposta perché i commenti di overflow sono nascosti sotto la risposta di Colin Ramsay: come di Reagire Native 0,28, è necessario anche alignItems: 'flex-start', nello styling listview o flexWrap non funzionerà. Grazie a Kerumen su codedump.io per questo. Quindi,

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

... con il resto come nella risposta di Colin.

+3

Questo è un commento così importante. Grazie :) – ppsreejith

+1

@kwishnu sei un dio! – kjonsson

+0

Non ho risposto su codedump. Era su StackOverflow;) http://stackoverflow.com/questions/39313268/react-native-grid-view-flexbox-wrap-not-working/39316901 – Kerumen

5

Seguire la risposta di Colin Ramsay. E se vuoi metà larghezza per ogni oggetto, prova in questo modo.

... 
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, 
    }, 
}); 
+0

Ho incasinato un sacco di tempo prima di inciampare nella tua risposta quaggiù. Grazie mille per questo! –

+0

prego. –

6

Ho avuto lo stesso problema e ho scritto un componente che risolve questo problema, si può trovare qui: https://github.com/pavlelekic/react-native-gridview

Inoltre, un'altra cosa questa componente non fa altro che fa in modo che gli elementi larghezza è un numero intero, in modo che i bordi degli elementi non abbiano antialiasing, siano chiari e nitidi.

+0

Funziona in 0.42. Spero che ottenga più attenzione. – RedGiant

+0

Questa dovrebbe essere la risposta giusta, grazie! – leo7r

+0

@Pavle Lekic, grazie per aver scritto quella libreria. Ho aggiunto un problema relativo a renderHeader che non ha dimensioni sull'intera larghezza. – pmont

8

ListView è ora deprecated e si consiglia di utilizzare FlatList. FlatList ha un supporto chiamato numColumns che è esattamente quello che vogliamo creare una griglia scorrevole.

Ad esempio:

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

Questo blog post fa un buon lavoro che spiega le nuove funzionalità di FlatList.

Nota: per qualche motivo è necessario utilizzare keyExtractor nella FlatList invece del tipico puntello key su ciascun articolo. Altrimenti riceverai un avvertimento. Basic FlatList code throws Warning - React Native

1

È possibile utilizzare FlatList e impostare numColonne per ottenere il risultato che è la stessa con la griglia

0

Controllare il seguente esempio utilizzando FlatList componente del Reagire nativo per supportare lo scorrimento infinito con una prestazione eccellente:

//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'esempio si presenta come

enter image description here

Cordiali saluti, Nicholls