React Native - Criando layouts - Parte 2

Imagem para React Native - Criando layouts - Parte 2

React nativePostado em  6 min de leitura

Dando continuidade ao artigo Criando Layouts. Na parte 1, vimos o Stack layout e agora vamos continuar vendo os tipos de layout que conseguimos criar no React native.

Grid Layout

O React Native não vem com um sistema de layout de grade, mas o flexbox é flexível o suficiente para criar um. Ao utilizar o que já vimos até agora, podemos recriar um grid layout usando o flexbox. Ex:

Stack Layout Vertical

import React, { Component } from 'react';
import {
  StyleSheet,
  View
} from 'react-native';

export default class GridLayout extends Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.row}>
          <View style={[styles.box, styles.box2]}></View>
          <View style={[styles.box, styles.box3]}></View>
          <View style={[styles.box, styles.two]}></View>
        </View>

        <View style={styles.row}>
          <View style={[styles.box, styles.two]}></View>
          <View style={[styles.box, styles.box2]}></View>
          <View style={[styles.box, styles.box3]}></View>
        </View>

        <View style={styles.row}>
          <View style={[styles.box, styles.box2]}></View>
          <View style={[styles.box, styles.two]}></View>
          <View style={[styles.box, styles.box3]}></View>
        </View>

        <View style={styles.row}>
          <View style={[styles.box, styles.box2]}></View>
          <View style={[styles.box]}></View>
          <View style={[styles.box, styles.box3]}></View>
        </View>

        <View style={styles.row}>
          <View style={[styles.box, styles.box2]}></View>
          <View style={[styles.box]}></View>
        </View>

        <View style={styles.row}>
          <View style={[styles.box]}></View>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: { flex: 1 },
  row: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginBottom: 10
  },
  box: {
    flex: 1,
    height: 100,
    backgroundColor: '#333',
  },
  box2: { backgroundColor: 'green' },
  box3: { backgroundColor: 'orange' },
  two: { flex: 2 }
});

No código acima, você pode ver que estamos simulando o que costumamos fazer em uma estrutura de grade no CSS. Cada linha com uma exibição separada e os itens da grade estão dentro dela. O valor 1 na propriedade flex é aplicado a cada item para que eles compartilhem igualmente o espaço disponível em cada linha. Mas para itens que precisam ocupar um espaço maior, um valor flex maior é aplicado. Isso ajusta automaticamente a largura dos outros itens para acomodar todos os itens.

Se você quiser adicionar espaços entre cada item de uma linha, você pode adicionar um preenchimento a cada um deles e criar uma caixa dentro de cada um. Ex:

Stack Layout Vertical

Absolute Layout

O React Native só suporta os valores absolutee relative, para a propriedade position. Isso não limita muito, porque sempre podemos combiná-los com o flexbox para posicionar os diferentes elementos em qualquer lugar que desejarmos. Ex:

Stack Layout Vertical

Podemos conseguir isso facilmente se tivermos um comando total sobre os valores de posicionamento disponíveis no navegador. Mas, como estamos no React Native, precisamos pensar primeiro no modo flexbox e usar o posicionamento CSS para as caixas.

Usando o flexbox, isso pode ser conseguido de duas maneiras. Você pode usar row ou columnpara a propriedade flexDirection no elemento pai. Usando o valor row no flexDirection, a tela seja dividida em três colunas. A primeira coluna conterá a caixa vermelha, a segunda coluna conterá as caixas azul, cinza e verde e a terceira conterá as caixas amarela e roxa.

import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';

export default class Positioning extends Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.left}>
          <View style={[styles.box, styles.bigRedBox]}>
          </View>
        </View>
        <View style={styles.middle}>
          <View style={[styles.box, styles.bigBlueBox]}>
            <View style={[styles.innerBox, styles.blackBox]}></View>
          </View>
          <View style={[styles.bigGrayBox]}></View>
          <View style={[styles.box, styles.bigGreenBox]}>
            <View style={[styles.innerBox, styles.blackBox]}></View>
          </View>
        </View>
        <View style={styles.right}>
          <View style={[styles.box, styles.bigYellowBox]}>
            <View style={[styles.innerBox, styles.blackBox]}></View>
          </View>
          <View style={[styles.innerBox, styles.purpleBox]}></View>
        </View>
      </View>
    );
  }
}

A primeira coluna tem apenas a caixa vermelha, basta definir a propriedade justifyContent com center no elemento pai que define a coluna. Como já vimos, o o valor default do flexDirection é column. Isto significa que se você definir justifyContent como center, os elementos filhos serão alinhados no centro do eixo Y.

A segunda coluna tem basicamente a mesma ideia que a primeira, só que desta vez não queremos alinhar todas as caixas ao centro. O que queremos é que eles tenham espaços iguais entre eles. A propriedade justifyContent com valor space-between, resolve isso. Mas ao mesmo tempo, também queremos centralizar os elementos filhos no eixo x, então nós usamos alignItems com valor center.

A única parte complicada aqui é que você não deve aplicar nenhuma propriedade width a caixa cinza porque queremos que ele ocupe todo o espaço do elemento pai. Uma vez que não aplicamos a propriedade width, devemos usar a propriedade alignSelf com valor stretch, para que a caixa cinza ocupe a largura total do seu elemento pai.

Em seguida, para posicionar a pequena caixa preta um pouco longe de sua posição relativa, usamos position com o valor relative e depois acrescentamos as propriedades top e left com os valores que queremos, porque sua posição relativa está em torno do canto superior esquerdo de seu pai.

Na pequena caixa roxa, colocamos a propriedade position com o valor absolute e as propriedades bottom e right, para alinhá-la ao canto inferior direito de seu pai. Isso funciona porque elementos posicionados com position: absolute no React Native estão vinculados aos seus pais.

A terceira coluna basicamente aplica a mesma ideia.

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
  },
  left: {
    flex: 1,
    justifyContent: 'center',
  },
  middle: {
    flex: 5,
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  right: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'flex-end',
  },
  box: {
    width: 100,
    height: 100,
    backgroundColor: '#f2f2f2',
  },
  bigGreenBox: { backgroundColor: 'green' },
  bigRedBox: { backgroundColor: 'red' },
  bigYellowBox: { backgroundColor: 'yellow' },
  bigGrayBox: {
    height: 100,
    alignSelf: 'stretch',
    backgroundColor: '#ccc'
  },
  innerBox: {
    width: 20,
    height: 20,
  },
  redBox: {
    position: 'relative',
    backgroundColor: 'red',
    top: 10,
    left: 10
  },
  blueBox: {
    position: 'absolute',
    backgroundColor: 'blue',
    top: 10,
    right: 10
  },
  purpleBox: {
    position: 'absolute',
    backgroundColor: 'purple',
    bottom: 10,
    right: 10
  },
  blackBox: {
    position: 'relative',
    backgroundColor: 'black',
  }
});

Header e footer fixos.

Para isso, precisamos usar o componente de ScrollView, se o conteúdo for maior que a altura do elemento, o React Native gerará automaticamente uma barra de rolagem vertical. Isso nos permite adicionar marginTop e marginBottom no elemento com o conteúdo principal, para que o header e o footer fixos não obstruam o conteúdo principal. Os valores de left e right do header e footer estão configurados com 0, para que eles ocupem a largura total do dispositivo.

import React, { Component } from 'react';
import { StyleSheet, View, ScrollView } from 'react-native';

export default class FixedHeaderFooter extends Component {
  render() {
      return (
      <View style={styles.container}>
        <View style={[styles.header]}></View>
        <ScrollView>
          <View style={[styles.content]}>
            <View style={[styles.box]}></View>
            <View style={[styles.box]}></View>
            <View style={[styles.box]}></View>
            <View style={[styles.box]}></View>
            <View style={[styles.box]}></View>
            <View style={[styles.box]}></View>
            <View style={[styles.box]}></View>
          </View>
        </ScrollView>
        <View style={[styles.footer]}></View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'center'
  },
  header: {
    height: 40,
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    backgroundColor: 'red,
    zIndex: 10
  },
  content: {
    alignItems: 'center',
    marginTop: 50,
    marginBottom: 40
  },
  footer: {
    height: 40,
    position: 'absolute',
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'blue'
  },
  box: {
    width: 100,
    height: 100,
    backgroundColor: 'gray',
    marginBottom: 10
  }
});

Conclusão

Vimos como usar o Flexbox do React Native para posicionar os elementos e criarmos os layouts. Espero que essas duas partes consigam te ajudar na tarefa de criação de layouts e que tenha ajudado a conhecer as propriedades mencionadas.

O repositório nexus-react-native/04-how-to-create-layouts, está a disposição para praticar. :)