As mobile app users, we love to see some diversity in how elements are being rendered in the app.
One way of presenting a list of items is through the use of horizontally rendered list of cards. Spotify is one of the application that successfully uses this pattern.
Let’s go through a short tutorial to create a horizontal card listing in react native.
What are we building
We are going to create a small app that renders list of cards horizontally. We are going to use the following component for this purpose:
- Create-react-native-app to get an app quickly
- FlatList from react native library
- React-native-elements to help out with the card
Application setup
Let’s start by creating our react native app. We’ll use create-react-native-app for this.
If you do not have create-react-native-app cli installed yet, follow the steps at create-react-native-app documentation.
To have a brand new react native app, simply run this in your command line.
npm install -g create-react-native-app
Next, we want to install react-native-elements. React-native-elements is a great UI components library that would reduce our design effort exponentially.
npm install --save react-native-elements
With this setup, we would have a react native app that can be run in expo, complete with react native elements.
Creating the card
We’ll use react native elements card to render our card quickly.
We will follow Spotify card, so the only items we would need are the description for the card and an image for the body of the card.
import React, { Component } from "react"; | |
import { Text } from "react-native"; | |
import { Card } from "react-native-elements"; | |
export default class App extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
data: data | |
}; | |
} | |
render() { | |
return ( | |
<Card | |
title={null} | |
image={{ uri: "http://via.placeholder.com/160x160" }} | |
containerStyle={{ padding: 0, width: 160 }} | |
> | |
<Text style={{ marginBottom: 10 }}> | |
hello | |
</Text> | |
</Card> | |
); | |
} | |
} |
We don’t want to have a title for this card, so we pass in null for the title. Additionally, we’d like to have a predefined width for the card so we can have react native flatList render the cards properly; we define this in containerStyle attribute on the card component.
Creating the list
For the list, we are using react native flatlist which is a component that is optimized to render list item.
For the renderRow method in the flatList, we will use card class that we created earlier.
import React, { Component } from "react"; | |
import { FlatList, Text } from "react-native"; | |
import { Card } from "react-native-elements"; | |
const data = [ | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something two" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something three" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something four" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something five" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something six" | |
} | |
]; | |
export default class App extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
data: data | |
}; | |
} | |
render() { | |
return ( | |
<FlatList | |
data={this.state.data} | |
renderItem={({ item: rowData }) => { | |
return ( | |
<Card | |
title={null} | |
image={{ uri: "http://via.placeholder.com/160x160" }} | |
containerStyle={{ padding: 0, width: 160 }} | |
> | |
<Text style={{ marginBottom: 10 }}> | |
hello | |
</Text> | |
</Card> | |
); | |
}} | |
keyExtractor={(item, index) => index} | |
/> | |
); | |
} | |
} |
We should now have a list of card rendered in our react native app albeit pretty static.
The data for FlatList is coming from the constant “data” that we declare above the class and set as the state in the component.
If you need more in depth context of listview and flatlist, you can check out my previous article on creating infinite list with listview and migrating listview to flatList.
Making a horizontal list
If you noticed, there’s something wrong with our list, it is a vertical list instead of a horizontal list!
Guess what, to get a horizontal list is really easy! Just add the horizontal
attribute to our list.
import React, { Component } from "react"; | |
import { FlatList, Text } from "react-native"; | |
import { Card } from "react-native-elements"; | |
const data = [ | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something two" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something three" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something four" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something five" | |
}, | |
{ | |
imageUrl: "http://via.placeholder.com/160x160", | |
title: "something six" | |
} | |
]; | |
export default class App extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
data: data | |
}; | |
} | |
render() { | |
return ( | |
<FlatList | |
horizontal | |
data={this.state.data} | |
renderItem={({ item: rowData }) => { | |
return ( | |
<Card | |
title={null} | |
image={{ uri: rowData.imageUrl }} | |
containerStyle={{ padding: 0, width: 160 }} | |
> | |
<Text style={{ marginBottom: 10 }}> | |
{rowData.title} | |
</Text> | |
</Card> | |
); | |
}} | |
keyExtractor={(item, index) => index} | |
/> | |
); | |
} | |
} |
On top of the horizontal attribute, for the card to pick up the proper data, we are making use of the item
properties passed on by flatList to each of our elements.
That’s it! With the fixed width set, our horizontal FlatList should now looks just how we want it! All we need to do is assign proper images and title, and we’re all set.
Let me know if I miss anything in the comment!