React Native: posicionando elementos com Flex

React Native: posicionando elementos com Flex
Matheus Alberto
Matheus Alberto

Compartilhe

Neste artigo, vamos descobrir como posicionar elementos na tela do celular com uma ferramenta importante do React Native: o Flex. E vamos conhecer:

  • O que é o Flex e para que serve;
  • Tamanho de telas e unidades de medida;
  • Números fixos e relativos;
  • Algumas propriedades do Flex.

Conhecer o Flex do React Native é muito importante para qualquer pessoa desenvolvedora de mobile.

Vamos lá?

Introdução

Um dos passos de desenvolver um aplicativo em mobile é o de cuidar da estilização e disposição de elementos em uma tela de celular. Existem diversos modelos de celulares, cada um com um tamanho de tela diferente. Como organizar, definir tamanhos e espaçamentos sem que elementos ultrapassem os limites do dispositivo? Ou evitar que sobrem espaços enormes nas laterais?

Flex é uma das ferramentas mais importantes para trabalhar com posicionamento de elementos no React Native. E, ao ler a palavra Flex, talvez lhe venha na cabeça algo como Flexbox do CSS.

Fazendo uma pequena comparação entre Flex (do React Native) e Flexbox (do CSS), ambos são semelhantes, mas possuem alguns valores iniciais diferentes e também algumas nomenclaturas diferentes. Mas, caso você já conheça Flexbox, não terá muitos problemas em entender Flex do React Native.

Antes de começar a explicar como Flex funciona, primeiro precisamos entender como funciona nosso "canvas" (podendo também fazer uma analogia com um quadro) e suas dimensões.

Cada celular, um canvas diferente

Cada dispositivo tem um tamanho de tela diferente e cada tela tem uma resolução diferente. Até aí, tudo bem. O problema começa quando comparamos as unidades de medida. Uma tela é medida em polegadas e a resolução de uma tela é medida em pixels.

Uma polegada não necessariamente tem um número fixo de pixels. Por exemplo, existem celulares de 4 polegadas que tem uma tela de resolução 720p (720 pixels), e existem celulares de 5 polegadas que tem uma tela de resolução 480p (480 pixels).

Essas informações são importantes, porque quando escrevemos "tamanho" em código, nós utilizamos a unidade de medida pixel. Por conta disso, cada celular vai mostrar elementos com tamanhos (físicos) diferentes mesmo que em código eles tenham o mesmo tamanho.

Uma solução para resolver essa inconsistência é utilizar unidades de medida relativas como porcentagem. Em React Native, nós utilizamos apenas duas unidades de medida: pixels ou px e porcentagem ou %.

É muito importante entender que não existe uma maneira certa ou uma unidade perfeita. Utilizamos px ou % dependendo da necessidade.

Porém, mesmo com unidades relativas, ainda encontramos algumas limitações. Vou usar o código abaixo como exemplo:

// App.js
import { StyleSheet, StatusBar, SafeAreaView, Text, View } from 'react-native';

export default function App() {
  return (
    <SafeAreaView>
      <StatusBar/>
      <View style={styles.quadradoA}/>
      <View style={styles.quadradoB}/>
      <View style={styles.quadradoC}/>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  quadradoA: {
    backgroundColor: "green",
    height: 100
  },
  quadradoB: {
    backgroundColor: "blue",
    height: 100
  },
  quadradoC: {
    backgroundColor: "orange",
    height: 100
  }
});

Tela de um celular com 3 retângulos alinhados ao topo que ocupam aproximadamente 1/8 da tela cada. O primeiro retângulo tem a cor verde, o segundo azul e o terceiro laranja.

Neste exemplo, foi definida uma altura de 100px para cada retângulo. Como podemos fazer para que cada retângulo ocupe 1/3 da tela do dispositivo?

Com unidades fixas como px fica muito difícil de definir. Cada dispositivo tem um tamanho de tela diferente, portanto, a altura pode variar.

Vamos ver como ficaria com a unidade relativa %. Para calcular a porcentagem de altura que cada retângulo deve ter, basta resolver a conta 1/3. O resultado é 33,33333333333333333...%. Bom... acho que já deu para perceber o problema aqui também: O número 33,333... não é um valor preciso. O ideal seria utilizar frações, mas o React Native não consegue trabalhar com esse tipo de valor. Então precisamos converter para %, o que acabou gerando a dízima periódica.

Ou seja, mesmo com porcentagens é complicado definir um tamanho exato para dimensionar e posicionar os elementos em tela. Como fazemos então?

O Flex veio para resolver

O Flex é uma ferramenta que veio para ajudar na disposição de elementos na tela do dispositivo. Mas a pergunta é: onde vamos aplicar a propriedade flex?

Primeiro, precisamos entender o que essa propriedade faz. Quando aplicamos flex em um componente, ele se transforma em um flex container. Todos os componentes que são descendentes diretos do flex container podem ser remanejados com outras propriedades de Flex, por exemplo, alinhamento vertical, alinhamento horizontal, espaçamento, entre outros.

Por padrão, todos os componentes já são um flex container, sem precisar definir nada. Mas, então, o que a propriedade flex faz? A propriedade flex diz qual o tamanho proporcional que o componente vai ocupar. Por padrão, o valor é 0. Ou seja, o componente só vai ocupar o espaço necessário para mostrar o conteúdo.

Vamos ver algumas propriedades de Flex e espaçar os retângulos pela página. Para isso, vamos utilizar a propriedade justifyContent. Esta propriedade pega todo o espaço restante dentro do flex container e divide entre os elementos. O valor que vamos utilizar é space-between.

import { StyleSheet, StatusBar, SafeAreaView, Text, View } from 'react-native';

export default function App() {
  return (
    <SafeAreaView style={styles.container}>
      <StatusBar/>
      <View style={styles.quadradoA}/>
      <View style={styles.quadradoB}/>
      <View style={styles.quadradoC}/>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    justifyContent: "space-between"
  },
  quadradoA: {
    backgroundColor: "green",
    height: 100
  },
  quadradoB: {
    backgroundColor: "blue",
    height: 100
  },
  quadradoC: {
    backgroundColor: "orange",
    height: 100
  }
});

Rodando o código acima, podemos perceber que não houve mudanças. O que será que aconteceu?

Primeiro vamos lembrar que, por padrão, o valor de flex é 0. Assim, o componente SafeAreaView só está ocupando o espaço necessário para mostrar os retângulos. Como a propriedade justifyContent distribui o espaço vazio entre os componentes e não existe espaço vazio dentro do flex container, os retângulos vão continuar grudados.

Para inserir um espaço entre os blocos coloridos,precisamos trocar o valor padrão de 0 para 1 na propriedade flex. Veja o código abaixo:

import { StyleSheet, StatusBar, SafeAreaView, Text, View } from 'react-native';

export default function App() {
  return (
    <SafeAreaView style={styles.container}>
      <StatusBar/>
      <View style={styles.quadradoA}/>
      <View style={styles.quadradoB}/>
      <View style={styles.quadradoC}/>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "space-between"
  },
  quadradoA: {
    backgroundColor: "green",
    height: 100
  },
  quadradoB: {
    backgroundColor: "blue",
    height: 100
  },
  quadradoC: {
    backgroundColor: "orange",
    height: 100
  }
});

Tela de celular com 3 retângulos, separados por espaços em branco, que ocupam aproximadamente 1/8 da tela cada. O primeiro retângulo de cor verde está no topo da tela, o segundo retângulo de cor azul está no meio da tela e o último retângulo de cor amarela está no final da tela.

Agora, os retângulos estão com um espaço entre si.

O que mais podemos fazer? Vamos alterar o fluxo dos componentes, da vertical (coluna) para a horizontal (linha). Para isso vamos usar a propriedade flexDirection.

import { StyleSheet, StatusBar, SafeAreaView, Text, View } from 'react-native';

export default function App() {
  return (
    <SafeAreaView style={styles.container}>
      <StatusBar/>
      <View style={styles.quadradoA}/>
      <View style={styles.quadradoB}/>
      <View style={styles.quadradoC}/>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "space-between",
    flexDirection: "row"
  },
  quadradoA: {
    backgroundColor: "green",
    height: 100
  },
  quadradoB: {
    backgroundColor: "blue",
    height: 100
  },
  quadradoC: {
    backgroundColor: "orange",
    height: 100
  }
});

Tela de celular em branco.

O resultado deve ser de uma tela vazia. Mas o que será que aconteceu? Por padrão, cada componente tem os valores de altura (height) e largura (width) como auto.

Para altura, auto significa altura mínima necessária para mostrar o componente.

Para largura, auto significa ocupar o máximo de espaço disponível. No entanto, quando mudamos algumas propriedades de Flex, por exemplo, a direção, auto significa largura mínima necessária para mostrar o componente.

Como os três componentes estão vazios, a sua largura vai ser de 0px: é por isso que a tela pareceu vazia.

Logo, vamos definir uma largura para esses retângulos. Temos duas opções para cada retângulo: utilizar a propriedade width ou a propriedade flex.

Para este exemplo, vou utilizar as duas maneiras com valores diferentes:

import { StyleSheet, StatusBar, SafeAreaView, Text, View } from 'react-native';

export default function App() {
  return (
    <SafeAreaView style={styles.container}>
      <StatusBar/>
      <View style={styles.quadradoA}/>
      <View style={styles.quadradoB}/>
      <View style={styles.quadradoC}/>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "space-between",
    flexDirection: "row"
  },
  quadradoA: {
    backgroundColor: "green",
    height: 100,
    width: 150,
  },
  quadradoB: {
    backgroundColor: "blue",
    height: 100,
    flex: 1,
  },
  quadradoC: {
    backgroundColor: "orange",
    height: 100,
    flex: 2,
  }
});

Com o código acima, obtemos o resultado mostrado na imagem abaixo:

Tela de celular com 3 retângulos alinhados horizontalmente no topo da tela. Os três ocupam aproximadamente 1/8 da altura da tela. O primeiro retângulo de cor verde ocupa aproximadamente 1/3 da largura da tela. O segundo retângulo de cor azul ocupa aproximadamente 1/5 da largura da tela. O último retângulo de cor laranja ocupa um pouco menos da metade da largura da tela.

O primeiro retângulo verde tem exatos 150px de largura, o retângulo azul ocupa 1/3 do espaço restante (largura da tela em pixels - 150px do primeiro retângulo) e o retângulo laranja ocupa duas vezes o espaço do retângulo azul.

Conclusão

Flex é uma ferramenta bem poderosa para posicionamento de elementos na tela. Existem muitas outras propriedades e valores de que não falei aqui no artigo. É interessante usar estes conceitos vistos aqui e testar o que os outros valores e propriedades fazem.

O link para a documentação oficial (em inglês) do Flex no React Native com exemplos interativos: Layout with Flexbox.

Gostou deste artigo? Tem sugestões? Marque a gente nas redes sociais!

Quer conhecer mais sobre React Native? Confira alguns de nossos cursos:

Matheus Alberto
Matheus Alberto

Formado em Sistemas de Informação na FIAP e em Design Gráfico na Escola Panamericana de Artes e Design. Trabalho como desenvolvedor e instrutor na Caelum e Alura. Nas horas vagas sou artista/ilustrador.

Veja outros artigos sobre Mobile