Blog Formação DEV

Tamanhos relativos em Flutter

Nesse artigo você verá a melhor forma de definir o tamanho de elementos em aplicativos Flutter, para manter o seu aplicativo funcional em diferentes dispositivos.
Tamanhos relativos em Flutter
Texto de: Lucas Galdino

Introdução

Hoje irei abordar um tema bem importante para se pensar na hora de fazer nossos aplicativos: os tamanhos relativos. Esses tipos de tamanhos permitem fazer com que os elementos na sua tela ocupem um espaço adequado em diferentes tamanhos de dispositivos, o que melhora bastante a experiência do usuário.

Criando projeto

Para iniciar vamos criar um projeto para demonstração com o comando abaixo:

flutter create tamanhos 

Após criar o projeto, vamos abrir ele no VSCode ou em qualquer editor de sua preferência. Editei um pouco o código inicial para ilustrar melhor os exemplos, então basta abrir o arquivo "main.dart" e deixar ele da seguinte maneira:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tamanhos Relativos',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Tamanhos Relativos'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              height: 50,
              width: 50,
              decoration: const BoxDecoration(
                color: Colors.red,
              ),
            ),
          ],
        ),
      ),
    );
  }
} 

O resultado vai ser uma simples tela limpa com um "Container" de 50 x 50 pixels na cor vermelha, dessa forma:

Tamanho absoluto

Quando falamos de tamanho absoluto estamos falando de colocar os números exatos como tamanho de um widget. No "Container" criado inicialmente utilizei o tamanho absoluto de 50 pixels de altura por 50 pixels de largura, ou seja, esse é tamanho exato do widget na tela.

É bem difícil que esse tamanho acabe gerando erro em algum aparelho, afinal, hoje em dia os celulares têm uma resolução bem alta e 50 x 50 é um tamanho pequeno. Porém, quando utilizamos tamanhos absolutos podemos nos deparar com um problema. O que acontece caso o tamanho utilizado ultrapasse o tamanho da tela? Vou editar o código para aumentar o "Container" de 50 x 50 para 5000 x 5000.

Container(
	height: 7000,
	width: 4000,
	decoration: BoxDecoration(
		color: Colors.blue,
	),
), 

O resultado na tela do aplicativo fica assim:

Recebemos também um aviso lá no log do VSCode. Basicamente é um simples aviso de que algum widget está ultrapassando os limites de pixels da tela do dispositivo sendo testado. Esse é um problema que pode acontecer sem percebermos, afinal, podemos estar fazendo testes em um dispositivo com uma tela de resolução alta e nunca ter um problema desse, mas considerando que a aplicação pode rodar em diferentes dispositivos, em algum momento, um aparelho com uma tela menor pode sofrer por conta disso.

Tamanhos relativos

A forma que temos para lidar com essa situação é utilizar tamanhos relativos. Para isso, precisamos apenas de dois dados simples, a altura e largura da tela em questão, ou seja, as dimensões do aparelho que está executando o aplicativo. O Flutter tem uma forma de obter os dados de tamanhos da tela onde o código está rodando, ou seja, o mesmo código vai trazer resultados diferentes dependendo do dispositivo que está executando o aplicativo no momento. Assim temos os tamanhos relativos para cada dispositivo. O código em questão é esse:

MediaQuery.of(context).size.height //para altura
MediaQuery.of(context).size.width //para largura 

O resultado desses códigos é o tamanho exato que o dispositivo possui. Podemos utilizar tais códigos diretamente no widget, dessa forma:

Container(
	height: MediaQuery.of(context).size.height,
	width: MediaQuery.of(context).size.width,
	decoration: BoxDecoration(
		color: Colors.red,
	),
), 

Apesar disso, o resultado vai parecer igual ao anterior, com mesmo erro e a mesma tela no emulador. Isso acontece por que utilizar o tamanho total da tela também vai ser um "erro". Todo celular por padrão vai acabar ocupando alguma parte da tela com elementos da interface do próprio sistema, como, por exemplo, a barra onde ficam os símbolos de wi-fi, a bateria e relógio e por isso não devemos utilizar todo o espaço disponível.

A forma correta de utilizar esse recurso vai requerer um pouco de matemática. Pensando na lógica por trás de tudo, temos que cada um desses valores contém 100% do tamanho da tela, ou seja, podemos pegar esse valor e dividir ele para usar tamanhos menores da tela. Para dividir precisamos apenas utilizar um método para fracionar esse valor, sendo que uma das formas, talvez a forma mais utilizada, é multiplicar o valor por algum valor entre 0 e 1. Ou seja, entre 0% e 100% do tamanho da tela.

No caso do exemplo abaixo, vou multiplicar tanto a altura quanto a largura por 0,3 que é referente a 30% dos tamanhos da altura e largura da tela do dispositivo. Se multiplicar por 1 é equivalente a 100% do tamanho, multiplicar por 0,3 é equivalente a 30% do tamanho. Aqui o código:

Container(
	height: MediaQuery.of(context).size.height * 0.3,
	width: MediaQuery.of(context).size.width * 0.3,
	decoration: BoxDecoration(
		color: Colors.red,
	),
), 

E o resultado desse código é o seguinte:

Podemos também obter esses dados e armazenar os valores de tamanho da tela em variáveis mais acima no código para poder utilizar tais valores em qualquer ponto da aplicação, o que deixa o código mais limpo. Dessa forma aqui:

final altura = MediaQuery.of(context).size.height;
final largura = MediaQuery.of(context).size.width; 

Como o contexto da aplicação é utilizado na definição das variáveis precisamos inserir esse código dentro do widget responsável pela build da página, dessa forma aqui:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    final altura = MediaQuery.of(context).size.height;
    final largura = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar 

Com tais variáveis disponíveis no código podemos utilizar elas da seguinte forma:

Container(
	height: altura * 0.5,
	width: largura * 0.8,
	decoration: BoxDecoration(
		color: Colors.red,
	),
), 

E o resultado é o seguinte:

Aqui está o código final do arquivo "main.dart" após todas as mudanças:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tamanhos Relativos',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Tamanhos Relativos'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    final altura = MediaQuery.of(context).size.height;
    final largura = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              height: altura * 0.5,
              width: largura * 0.8,
              decoration: const BoxDecoration(
                color: Colors.red,
              ),
            ),
          ],
        ),
      ),
    );
  }
} 

Conclusão

Então é isso galera. Fiquem de olho nessa questão em seus projetos, pois é algo super importante para manter seu aplicativo funcionando em qualquer tipo de dispositivo e também algo importante se fazer com qualquer widget para evitar problemas no seu projeto no geral. Bons estudos!

Sobre o autor
Cod3r

Cod3r

Com mais de 400 mil alunos, a Cod3r é uma das principais escolas de tecnologia do País. Um de seus produtos mais importantes é a Formação DEV, com objetivo de preparar os profissionais para o mercado.

Ótimo! Inscreveu-se com sucesso.

Bem-vindo de volta! Registou-se com sucesso.

Assinou com sucesso o Blog Formação DEV .

Sucesso! Verifique o seu e-mail para obter o link mágico para se inscrever.

As suas informações de pagamento foram atualizadas.

Seu pagamento não foi atualizado.