GridView

Similar to ListView, GridView is used to render Grid of items.

GridView (GridRow) example

Instead of having a separate GridView component, you should use GridRow component to encapsulate a single row of items (cells), and then pass the GridRow as a normal row to a ListView component which does the actual content rendering.

The main idea behind this approach is to allow developers to have a variable number of columns in each row, for example, the first row can have only 1 column, followed by a number of rows with 2 columns.

API

Props

  • columns: number
    • Number of columns in the GridRow

Style names

GridView has no specific style names.

Methods

  • groupByRows(data: array, columns: number, getColumnSpan: function)
    • data: array containing all items.
    • columns: number defining number of columns in grid.
    • getColumnSpan: function (optional) returns the column span of a single element. Each element has a span of 1 by default.
    • returns an array of rows, where each row is an array of data elements.

Example

GridView (GridRow) example

JSX declaration

constructor(props) {
  super(props);
  this.renderRow = this.renderRow.bind(this);
  this.state = {
    restaurants: [
      {
        "name": "Gaspar Brasserie",
        "address": "185 Sutter St, San Francisco, CA 94109",
        "image": { "url": "https://shoutem.github.io/static/getting-started/restaurant-1.jpg" },
      },
      {
        "name": "Chalk Point Kitchen",
        "address": "527 Broome St, New York, NY 10013",
        "image": { "url": "https://shoutem.github.io/static/getting-started/restaurant-2.jpg" },
      },
      {
        "name": "Kyoto Amber Upper East",
        "address": "225 Mulberry St, New York, NY 10012",
        "image": { "url": "https://shoutem.github.io/static/getting-started/restaurant-3.jpg" },
      }
    ],
  }
}

renderRow(rowData, sectionId, index) {
  // rowData contains grouped data for one row,
  // so we need to remap it into cells and pass to GridRow
  if (index === '0') {
    return (
      <TouchableOpacity key={index}>
        <ImageBackground
          styleName="large"
          source={{ uri: rowData[0].image.url }}
        >
          <Tile>
            <Title styleName="md-gutter-bottom">{rowData[0].name}</Title>
            <Subtitle styleName="sm-gutter-horizontal">{rowData[0].address}</Subtitle>
          </Tile>
        </ImageBackground>
        <Divider styleName="line" />
      </TouchableOpacity>
    );
  }

  const cellViews = rowData.map((restaurant, id) => {
    return (
      <TouchableOpacity key={id} styleName="flexible">
        <Card styleName="flexible">
          <Image
            styleName="medium-wide"
            source={{ uri: restaurant.image.url  }}
          />
          <View styleName="content">
            <Subtitle numberOfLines={3}>{restaurant.name}</Subtitle>
            <View styleName="horizontal">
              <Caption styleName="collapsible" numberOfLines={2}>{restaurant.address}</Caption>
            </View>
          </View>
        </Card>
      </TouchableOpacity>
    );
  });

  return (
    <GridRow columns={2}>
      {cellViews}
    </GridRow>
  );
}

render() {
  const restaurants = this.state.restaurants;
  // Group the restaurants into rows with 2 columns, except for the
  // first restaurant. The first restaurant is treated as a featured restaurant
  let isFirstArticle = true;
  const groupedData = GridRow.groupByRows(restaurants, 2, () => {
    if (isFirstArticle) {
      isFirstArticle = false;
      return 2;
    }
    return 1;
  });

  return (
    <Screen>
      <NavigationBar
        title="Restaurants"
        styleName="inline"
      />
      <ListView
        data={groupedData}
        renderRow={this.renderRow}
      />
    </Screen>
  );
}