React Native の ListView で２カラムの表示を簡単に

こんな感じのものをReactNativeでさくっと作る方法です。

<img width="375" alt="IMG_4422.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/821/f0c8d302-c13e-d06f-aa83-a2082d17442b.png">

Spotify の API　を叩いて `the` のつくアーティスト一覧を表示しています。

コードはこちらにおいているので適宜参照いただければと思います。
https://github.com/mataki/react-native-listvew-two-column

# まずはシンプルなリストビューとして表示する段階

<img width="375" alt="IMG_4419.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/821/d985bb36-8104-5ff6-5263-a50ff02e5bd9.png">

````js
  renderRow(data) {
    return (
      <View style={{ padding: 10, backgroundColor: 'white', margin: 5 }}>
        <Text>{data.name}</Text>
      </View>
    )
  }

  render() {
    return (
      <ListView
        style={{ flex: 1, paddingTop: 20, backgroundColor: '#dddddd' }}
        dataSource={this.state.dataSource}
        renderRow={this.renderRow}
        />
    );
  }
````

基本的な　ListView のサンプルだと思います。アーティスト名を一覧表示しています。

# 横にならぶようにする

こんな感じ

<img width="375" alt="IMG_4420.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/821/04964d3c-e62e-2227-8e63-4efb2f9f2313.png">

````diff
diff --git a/main.js b/main.js
index 8b09616..00fdb1f 100644
--- a/main.js
+++ b/main.js
@@ -34,7 +34,7 @@ class App extends React.Component {
   renderRow(data) {
     console.log(data)
     return (
-      <View style={{ padding: 10, backgroundColor: 'white', margin: 5 }}>
+      <View style={{ padding: 10, backgroundColor: 'white', margin: 5, width: 100, height: 100 }}>
         <Text>{data.name}</Text>
       </View>
     )
@@ -51,6 +51,7 @@ class App extends React.Component {
     return (
       <ListView
         style={{ flex: 1, paddingTop: 20, backgroundColor: '#dddddd' }}
+        contentContainerStyle={{ flexDirection: 'row', flexWrap: 'wrap' }}
         dataSource={this.state.dataSource}
         renderRow={this.renderRow}
         />
````

ポイントは、 `contentContainerStyle` の属性の追加です。これで横向きにアイテムをならるように指定します。ここでは、リストの内容は適当に 100x100 のサイズにしています。

# 2カラムに横幅を調整する

では、横幅をいい感じに調整してみましょう。こんな感じです。

<img width="375" alt="IMG_4421.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/821/abdd5332-0a4e-bd05-ea7d-9b050e613c14.png">

````diff
diff --git a/main.js b/main.js
index 00fdb1f..d203fe5 100644
--- a/main.js
+++ b/main.js
@@ -5,6 +5,7 @@ import {
   Text,
   View,
   ListView,
+  Dimensions,
 } from 'react-native';
 
 class App extends React.Component {
@@ -17,6 +18,9 @@ class App extends React.Component {
       isLoading: true,
       dataSource: ds.cloneWithRows([1, 2]),
     };
+
+    this.itemWidth = (Dimensions.get('window').width - 20) / 2;
+    this.renderRow = this.renderRow.bind(this)
   }
 
   componentWillMount() {
@@ -34,7 +38,7 @@ class App extends React.Component {
   renderRow(data) {
     console.log(data)
     return (
-      <View style={{ padding: 10, backgroundColor: 'white', margin: 5, width: 100, height: 100 }}>
+      <View style={{ padding: 10, backgroundColor: 'white', margin: 5, width: this.itemWidth, height: 100 }}>
         <Text>{data.name}</Text>
       </View>
````

`Dimensions` を使って画面の横幅を取得し、マージン分を調整して半分にします。

# 完成

あとは、画像を入れるなりして完成ですね。

<img width="375" alt="IMG_4422.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/821/f0c8d302-c13e-d06f-aa83-a2082d17442b.png">

````diff
diff --git a/main.js b/main.js
index d203fe5..682f529 100644
--- a/main.js
+++ b/main.js
@@ -4,6 +4,7 @@ import {
   StyleSheet,
   Text,
   View,
+  Image,
   ListView,
   Dimensions,
 } from 'react-native';
@@ -36,10 +37,14 @@ class App extends React.Component {
   }
 
   renderRow(data) {
-    console.log(data)
+    const image = data.images[0]
     return (
-      <View style={{ padding: 10, backgroundColor: 'white', margin: 5, width: this.itemWidth, height: 100 }}>
-        <Text>{data.name}</Text>
+      <View style={{ backgroundColor: 'white', margin: 5, width: this.itemWidth, height: 200, borderRadius: 2, overflow: 'hidden' }}>
+        <Image source={{ uri: image.url }} style={{ flex: 1, height: 50 }}/>
+        <View style={{ padding: 10 }}>
+          <Text style={{ fontSize: 14, fontWeight: '600', marginBottom: 5 }}>{data.name}</Text>
+          <Text style={{ fontSize: 11, color: '#555555'}}>{data.genres.slice(0, 3).join(', ')}</Text>
+        </View>
       </View>
     )
   }
````

# まとめ

とても簡単に横並びの一覧表示が出来たと思います。Flexboxの表現力ならではかなと思います。Flexboxに慣れていない段階だと ReactNative のレイアウトはなかなか勘所が難しいですが、慣れてくると気持ちよく出来るようになってくると思います。Flexboxいいよ！

[React Native Advent Calendar 2016](http://qiita.com/advent-calendar/2016/react-native) 3日目 の [Exponent で React Native のサンプルをさくっと公開する](http://qiita.com/mat_aki/items/b0ded9b07f896ded9bc9) で紹介した Exponent でサンプルを公開しています。こちらも触ってみていただけると動きも見れてよいかと思います。タップすると Spotify のページが開くようにもしてみました。[差分](https://github.com/mataki/react-native-listvew-two-column/commits/master)

https://exp.host/@mat_aki/listview-two-column