Flutter - Apresentando Layouts - V


Hoje veremos o conceito de Layouts no Flutter. (baseado na documentação oficial)

O Flutter é um SDK de aplicativo móvel do Google que ajuda a criar aplicativos móveis modernos para iOS e Android usando uma única (quase) base de código.

Se você não conhece o Flutter veja o meu artigo :  Flutter - Primeiros contatos e impressões

Continuando a quarta parte do artigo vamos tratar a interação com o usuário.

Interagindo com o usuário

Até o momento vimos que os widgets são modelos ou templates para tudo o que você pode ver (e muitas coisas que você não consegue ver) na interface do usuário. Vimos também que widgets simples podem ser combinados para criar layouts complexos. A maioria desses layouts pode ser construída dividindo seu design em linhas (widget Row), colunas (widget Colunm) e camadas (widget Stack).

Tudo bem, mas até o momento todos esses layouts usados eram estáticos. Eles não interagem com ninguém e não reagem a nenhuma ação, ou seja não fazem nada.

Neste artigo vamos explorar como realmente fazer algo quando o usuário interage com os widgets que adicionamos ao nosso layout. A ênfase será em exemplos simples e fáceis de reproduzir. Eu recomendo que você trabalhe enquanto passamos por cada um deles. Faça pequenas alterações no código e veja como isso afeta o comportamento. Isso aumentará muito o seu aprendizado geral.

Widgets e o estado(State)

Os Widgets são imutáveis. Ou seja, eles não podem ser alterados. Quaisquer propriedades que eles contenham são finais e só podem ser definidas quando o widget for inicializado. Isso os mantém leves, de modo que é barato recriá-los quando a árvore de widgets for alterada.

Assim, existem dois tipos de widgets:

  1. Sem estado - StatelessWidget
  2. Com estado - StatefulWidget

Em nosso exemplos estamos usando widgets sem estado ou StatelessWidget.

Os StatelessWidgets não possuem nenhum estado. Ou seja, eles não têm variáveis ​​mutáveis. Então, se temos uma variável que queremos mudar, então precisamos usar um StatefulWidget ou um widget com estado.

Os StatefulWidgets funcionam assim:

- Existe uma classe StatefulWidget e uma classe State.
- A classe StatefulWidget inicializa a classe State.
- A classe State contém as variáveis ​​e informa a classe StatefulWidget quando e como se construir.

Dessa forma sempre que precisarmos de um StatefulWidget, temos que criar duas classes:

  1. Uma classe do widget que estende de SatefulWidget;
  2. Uma classe de estado (State) que possui um método build();

Aqui está a configuração básica da estrutura de um StatefulWidget :

    // a classe do widget class
    class MeuWidget extends StatefulWidget {
      @override
      _MeuWidgetState createState() => _MeuWidgetState();
    }

    // a classe de estado ou state
    class _MeuWidgetState extends State<MeuWidget> {
      @override
      Widget build(BuildContext context) {
        return ...; // widget layout
      }
    }

Note que :

Agora que já sabemos como os Widgets se comportam vamos usar widgets que respondem a ação do usuário.

Vamos criar um projeto no VS Code chamado flutter_entrada_usuario e definir o código abaixo no arquivo main.dart :

 import 'package:flutter/material.dart';
    void main() => runApp(MyApp());
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter',
          home: Scaffold(
            appBar: AppBar(
              title: Text('Flutter'),
            ),
            body: MeuWidget(),
          ),
        );
      }
    }

Neste código definindo o método main() e criando um widget sem estado StatelessWidget chamado MyApp que usa o MaterialApp, o Scaffold e define um AppBar com texto.

Na propriedade body definimos o widget MeuWidget que iremos criar a seguir. Esse widget possui estado e deve estender de StatefulWidget.

Usando widgets responsivos

1- Button

Os Buttons são muito usados e o Flutter tem vários tipos de widgets Buttons como :

Vamos agora definir o widget MeuWidget como um widget com estado que deve herdar de StatefulWidget.

Como estamos usando o VS Code podemos usar atalhos para gerar trechos de código padronizados.

A extensão Flutter inclui os seguintes atalhos:

- Prefixo stless: Crie uma nova subclasse de StatelessWidget.
- Prefixo stful: crie uma nova subclasse de StatefulWidget e sua subclasse de estado associada.
- Prefixo stanim: crie uma nova subclasse de StatefulWidget e sua subclasse de estado associada, incluindo um campo inicializado com um AnimationController.

Então para criar um StatefulWidget digitamos stful e veremos as opções disponíveis:

Selecionando : Flutter stateful widget veremos o bloco de código gerado abaixo. Basta então completa digitando o nome da classe: MeuWidget.

Vamos então completar o código definindo no widget MeuWidget usando um Column com dois filhos: Text e RaisedButton, onde no Button definimos o método onPressed() fazendo uma chamada para o método _fazerAlgo():

    class MeuWidget extends StatefulWidget {
      @override
      _MeuWidgetState createState() => _MeuWidgetState();
    }
    String _textoString = "Macoratti .net -  Flutter";    
   class _MeuWidgetState extends State<MeuWidget> 
   {
         @override
         Widget build(BuildContext context) {
           return Column(
             children: <Widget>[
               Text(_textoString, style: TextStyle(fontSize: 30),
               ),
               RaisedButton(
                 child: Text('Meu Botão'), onPressed: () {
                   _fazerAlgo();
                 }
               ),
             ],
           );
       }
       void _fazerAlgo() {
        // Usando a chamada State.setState() estado atualizando
        // o valor do state da variável _textoString.
        setState(() {
          _textoString = 'Olá Flutter';
        });
      }
  }

Executando o código e pressionando no botão agora veremos que o valor do texto vai ser alterado de 'Macoratti .net - Flutter' para 'Olá Flutter'.

Aqui destacamos o seguinte:

2- TextFields

O widget textfield permite que o usuário insira texto, seja com o teclado do hardware ou com um teclado na tela.

Este widget chama o callback onChanged sempre que o usuário altera o texto no campo. Se o usuário indicar que está pronto para digitar no campo (por exemplo, pressionando um botão no teclado virtual), o campo de texto chama o callback onSubmitted.

Neste exemplo vamos criar um layout contendo um widget Text e um widget TextField onde sempre que o TextField mudar o valor de Text será atualizado.

Substitua o código da classe _MeuWidgetState pelo código a seguir:

class MeuWidget extends StatefulWidget {
      @override
      _MeuWidgetState createState() => _MeuWidgetState();
    }
    String _textoString = "Macoratti .net -  Flutter";    
    class _MeuWidgetState extends State<MeuWidget> {
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            Text(_textoString, 
            style: TextStyle(fontSize: 20),
            ),
            TextField(
              onChanged: (texto) {
                 _fazerAlgo(texto);
              },
            )
          ],
        );
    }
    void _fazerAlgo(String texto) {
         // Usando a chamada State.setState() estado atualizando
        // o valor do state da variável _textoString.
        setState(() {
          _textoString = texto;
        });
      }
    }

Observe que o widget TextField tem um parâmetro onChanged para um método de retorno de chamada. Este método fornece a string atual após uma alteração ter sido feita.

Se você deseja obter o valor do texto sem ouvir onChanged, é possível definir o parâmetro Controller do TextField.

2- Checkboxes

A caixa de seleção não mantém nenhum estado. Em vez disso, quando o estado da caixa de seleção é alterado, o widget chama o callback onChanged. A maioria dos widgets que usam uma caixa de seleção escutará o callback onChanged e reconstruirá a caixa de seleção com um novo valor para atualizar a aparência visual da caixa de seleção.

A caixa de seleção pode exibir, opcionalmente, três valores - true, false e null - se a propriedade tristate for true. Quando o valor é null, um traço é exibido. Por padrão, tristate é false e o valor da caixa de seleção deve ser true ou false.

Para o exemplo deste artigo vamos usar um CheckboxListTile que combina uma caixa de seleção com uma label.

Substitua o código da classe _MeuWidgetState pelo código a seguir:

   class MeuWidget extends StatefulWidget {
      @override
      _MeuWidgetState createState() => _MeuWidgetState();
    }
    bool _checkedValue = false;    
    class _MeuWidgetState extends State<MeuWidget> {
      @override
      Widget build(BuildContext context) {
         return CheckboxListTile( 
          title: Text('Este é um título'),
          value: _checkedValue,
          onChanged: (novoValor) {
            _fazerAlgo(novoValor);
          },
          // definindo o controlAffinity para leading faz 
          // com que a caixa de seleção seja exibida antes 
          //do título em vez de depois
          controlAffinity: ListTileControlAffinity.leading,
        );
      }
    void _fazerAlgo(bool isChecked) {
        // Usando a chamada State.setState() estado atualizando
        // o valor do state da variável _textoString.
        setState(() {
          _checkedValue = isChecked;
        });
      }
    }

Se você quiser criar uma caixa de seleção personalizada, poderá usar o widget Checkbox que não tem um título incluído.

Tente comentar a linha controlAffinity para ver como isso afeta o layout.

3- Dialogs

Existem alguns tipos de diálogos no Flutter, mas vamos ver um comum: o AlertDialog que não é difícil de configurar e que contém uma mensagem e alguns botões.

Nota: O widget Dialog não tem opinião sobre o conteúdo do diálogo. Em vez de usar esse widget diretamente, considere o uso de AlertDialog ou SimpleDialog, que implementam tipos específicos de diálogos de material design.

Substitua o código da classe _MeuWidgetState pelo código a seguir:

  class MeuWidget extends StatefulWidget {
      @override
      _MeuWidgetState createState() => _MeuWidgetState();
    }
    class _MeuWidgetState extends State<MeuWidget> {
      @override
      Widget build(BuildContext context) {
        return RaisedButton(
          child: Text('Clique Aqui para ver o Dialog'),
          onPressed: () {
            _showAlertDialog();
          },
        );
      }
      void _showAlertDialog() {
        // configura o button
        Widget okButton = FlatButton(
          child: Text("OK"),
          onPressed: () {
            // Navigator fecha a caixa de diálogo.
            //`context` significa o BuildContext, 
            // que esta disponível por padrão dentro de
            // um objeto State. Se você está trabalhando
            // com um AlertDialog em um StatelessWidget, 
            // então você precisaria passar uma referência 
            // ao BuildContext.
            Navigator.pop(context);
          },
        );
        // configura um AlertDialog
        AlertDialog alert = AlertDialog(
          title: Text("Titulo do Dialog"),
          content: Text("Este é um AlertDialog."),
          actions: [
            okButton,
          ],
        );
        // exibe o dialog
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return alert;
          },
        );
    }
}

Um AlertDialog precisa do BuildContext. Isso é passado para o método build() e também é uma propriedade do objeto State.

O widget Navigator é usado para fechar o diálogo e gerencia um conjunto de widgets filhos com uma disciplina de pilha.

Na próxima parte do artigo iremos tratar dos detectores de gestos.

"Arrependei-vos, pois, e convertei-vos, para que sejam apagados os vossos pecados, e venham assim os tempos do refrigério pela presença do Senhor,
E envie ele a Jesus Cristo, que já dantes vos foi pregado."

Atos 3:19-20

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti