Flutter - Calculadora Básica


Hoje veremos como criar uma calculadora bem básica usando poucas linhas de código.

Se você procurar, vai encontrar dezenas de código fonte mostrando como criar uma calculadora com o Flutter. Existem as mais diversas opções com calculadoras de todo o tipo e complexidade.

Nosso objetivo aqui será apresentar a criação de uma calculadora que realize as 4 operações usando a menor quantidade de código possível.

Abaixo vemos a nossa calculadora em execução:

Vejamos a seguir como criar o projeto.

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

Criando a calculadora básica

No Visual Studio Code tecle CTRL+ SHIFT+P para abrir a paleta de comandos e a seguir selecione a opção : Fluter:New Project;

A seguir informe o nome do projeto : flutter_calc e tecle ENTER;

Nosso projeto vai possuir apenas um único arquivo, o arquivo main.dart e vamos usar apenas um StatefulWidget chamado MyApp() :

import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
typedef OperadorFunc = double Function(double valor, double operando);
class MyApp extends StatefulWidget {
  @override
  MyAppState createState() {return new MyAppState();}
}

No código acima estamos definindo uma typedef chamada OperadorFunc e usando a biblioteca dart:math que contém constantes e funções mais um gerador de números aleatórios.

Uma typedef, ou um alias de tipo de função, ajuda a definir ponteiros para o código executável na memória. Assim, uma typedef pode ser usado como um ponteiro que faz referência a uma função.

A sintaxe básica usada é :  typedef function_name(parameters)

A seguir vamos definir o código na classe que estende State onde vamos definir o layout do projeto usando o MaterialApp e usando o widget Column estamos definido os widgets usados para compor o leiaute:

class MyAppState extends State<MyApp> {
  double valor = 0.0;
  double operando = 0.0;
  OperadorFunc filadeOperacao;
  String resultadoString = "0.0";
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,  
      home: SafeArea(
          child: Material(color: Colors.black,
            child: Column( 
              crossAxisAlignment: CrossAxisAlignment.end,
                children: <Widget>[
                  Expanded(
                    child: 
                      Row(crossAxisAlignment: CrossAxisAlignment.center, 
                        mainAxisAlignment: MainAxisAlignment.end, 
                        children: 
                          [
                             Text(resultadoString,textAlign: TextAlign.right, 
                              style: 
                              TextStyle(fontSize: 50.0, color: Colors.white),
                            )
                          ]
                  )
             ),
            buildRow(3,7,1,"/", (valor, divisor)=> valor / divisor , 1),
            buildRow(3,4,1,"x", (valor, divisor)=> valor * divisor , 1),
            buildRow(3,1,1,"-", (valor, divisor)=> valor - divisor , 1),
            buildRow(1,0,3,"+", (valor, divisor)=> valor + divisor , 1),
            Expanded(
              child:
                 Row(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children:
                    [
                      buildOperadorBotoes("C", null, 1, color: Colors.blueGrey),
                      buildOperadorBotoes("=", (valor, divisor)=> valor, 3)
                   ],
                 ),
             )
          ],
          ),
        ),
      )
    );
  }

No código acima vale destacar o widget SafeArea que é um widget de Padding glorificado. Se você agrupar outro widget com a SafeArea, ele adicionará qualquer preenchimento necessário para impedir que o widget seja bloqueado pela barra de status do sistema, furos, cantos arredondados e outros recursos dos fabricantes.

Agora precisamos definir os métodos usados no statefulwidget:

Abaixo temos a implementação dos métodos para dar vida a nossa calculadora.

...
void numeroPressionado(int valor)  {
    operando = operando * 10 + valor;
    setState(
          () => resultadoString = operando.toString()
      );
  }
  void calcular(OperadorFunc operacao) {
      if (operacao == null) {
        valor = 0.0;
      }else{
        valor = filadeOperacao != null ? filadeOperacao(valor, operando) : operando;
      }
      filadeOperacao = operacao;
      operando = 0.0;
      var resultado = valor.toString();
      setState(
        () => resultadoString = resultado.toString().substring(0, min(10,resultado.length))
      );
  }
  buildNumeroBotoes( int count,int from, int flex) {
    return Iterable.generate(count, (index)
    {
            return Expanded(flex: flex,
             child: Padding(
               padding: const EdgeInsets.all(1.0),
              child: FlatButton(
                      onPressed: () => numeroPressionado(from + index), color: Colors.white,
                        child: 
                           Text("${from + index}", 
                           style: TextStyle(fontSize: 40.0),
                        )
              ),
       ),
    );
   }).toList();
  }
 buildOperadorBotoes(String label, OperadorFunc func,
    int flex, {Color color = Colors.blue}){
      return Expanded(flex: flex,
           child: Padding(
             padding: const EdgeInsets.all(1.0),
              child: FlatButton(onPressed: () => calcular(func), color: color, 
                child: Text(
                      label, 
                      style: TextStyle(fontSize: 40.0),
                      )
              ),
          ),
      );
  }
 buildRow(int numberKeyCount, int startNumber,  int numberFlex, String operationLabel, 
  OperadorFunc operacao, int operrationFlex){
    return Expanded(child: 
     Row(crossAxisAlignment: CrossAxisAlignment.stretch,
       children: List.from(
             buildNumeroBotoes(numberKeyCount,startNumber ,numberFlex,)
          )
       ..add(
         buildOperadorBotoes(operationLabel, operacao, operrationFlex)
       )
     )
    );
  }
...

Observe que nos métodos numeroPressionado() e calcular() estamos usando o método setState() para notificar o framework da mudança de estado e atualizar a interface.

Pegue o projeto completo aqui: main_calc.dart

"Quão amáveis são os teus tabernáculos, SENHOR dos Exércitos!
A minha alma está desejosa, e desfalece pelos átrios do Senhor; o meu coração e a minha carne clamam pelo Deus vivo."

Salmos 84:1-2

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