Baixe o app para aproveitar ainda mais
Prévia do material em texto
TÉCNICO EM INFORMÁTICA 1. Introdução Em geral desenvolver uma aplicação mobile é uma tarefa desafiante e complexa. Há muitos frameworks disponíveis para desenvolver uma aplicação mobile. O Android fornece um framework nativo baseado na linguagem Java e o iOS fornece um framework nativo baseado na linguagem Shift / Objective-C. Contudo para desenvolver uma aplicação que suporte os dois SOs, precisamos codificar em duas linguagens diferentes usando dois frameworks diferentes. Para ajudar a superar esta complexidade que existe nos framework mobile que suportam ambos SOs. Esses frameworks variam de simples framework para aplicações mobile baseados em HTML (Os quais usam HTML como interface de usuário e JavaScript para a lógica da aplicação) a frameworks específicos como linguagem complexa (que faz o trabalho pesado de converter seus códigos para código nativo). Independente de sua simplicidade ou complexidade, esses frameworks sempre tem muitas desvantagens, uma das principais desvantagens é o baixo desempenho. Neste cenário, Flutter - um framework de alto desempenho e simples baseado na linguagem Dart, disponibiliza alta performance pela renderização da interface do usuário diretamente no canvas do sistemas operacionais e não por meio de um framework nativo. Flutter também oferece muitos widgets (UI) prontos para uso para criar uma aplicação moderna. Esses widgets são otimizados para o ambiente mobile e design de aplicações usando widgets é tão simples como o design HTML. Para ser específico, uma aplicação Flutter é um widget. Widgets Flutter também suporta animações e gestos. A lógica da aplicação é baseada na programação reativa. Widget podem opcionalmente ter um estado. Mudando o estado do widget, irá automaticamente (programação reativa) comparar o estado do widget (novo e antigo) e renderizar o widget com somente as mudanças necessárias ao invés de renderizar o widget inteiro novamente. 1.1. O que é programação reativa? Programação reativa é um modelo de programação sobre fluxos de dados, potencialmente assíncronos, em combinação com consumo/roteamento de eventos e propagação de estado. 1.2. Por que Programação Reativa? Um dos desafios da Engenharia de Software atualmente são aplicações orientadas a alto volumes de dados em tempo real. Usuários querem seus dados agora; querem ver seus tweets agora, confirmar seus pedidos agora, jogos online precisam responder agora! TÉCNICO EM INFORMÁTICA As aplicações precisam igualmente responder a essas demandas agora. Não queremos que nosso software fique bloqueado por um pedido de informações ou aguardando o resultado de uma computação. Não queremos que nossa aplicação fique parada aguardando algum resultado, mas precisamos exibi-los assim que estiverem prontos. Se lidamos com um bloco de informações, queremos manipular resultados individuais, e não esperar que o conjunto inteiro seja processado. O comportamento das aplicações evoluiu para lidar com dados empurrados. Então, precisamos de ferramentas de implementação para construir um código capaz de reagir a eventos e informações. 1.3. Para que usar Programação Reativa? Alguns casos de uso onde a programação reativa pode fazer sentido são: Eventos de UI (movimento do mouse, clicks de botão, etc): programadores desse tipo de aplicação (digamos, em Javascript ou Android) estão acostumados a lidar com eventos de componentes, então não há nada fundamentalmente diferente. As vantagens do paradigma reativo surgem com o conjunto de operadores disponíveis para manipulação dos eventos, tornando simples tarefas como, por exemplo, throttle de múltiplos clicks ou propagação de eventos para interfaces hiper-interativas; Chamadas para serviços externos (REST, RPC, etc): operações realizadas sobre HTTP são bloqueantes por natureza; ao fornecer uma simplificação para o código assíncrono, a programação reativa pode ajudá-lo a desbloquear o código de cliente HTTP, mas essa é a parte mais simples. Em arquiteturas de serviços distribuídos (como microserviços), é comum um código de back-end construir uma composição entre várias chamadas dependentes (o serviço “a” é invocado, e a resposta é utilizada como parâmetro para invocar o serviço “b”, e sucessivamente). Frameworks reativos podem ajudar a orquestrar chamadas dependentes de maneira natural, com a vantagem de NÃO bloquear o código no cliente. Consumo de mensagens: processamento de mensagens com alta concorrência é um caso de uso comum. Declaradamente, frameworks como o próprio RxJava, Reactor ou o Akka alegam serem capazes de processar milhões de mensagens por segundo na JVM sem esforço. Sendo isso verdade ou não, em maior ou menor grau, novamente sua implementação pode se beneficiar das ferramentas disponíveis nesses frameworks para construir um pipeline de consumo de eventos/mensagens de maneira muito simples. Abstração sobre processamento assíncrono: esse detalhe vai depender da ferramenta e da linguagem que estiver utilizando, mas um dos pontos-chave dos frameworks reativos é fornecer uma fundação simples para processamento assíncrono, desafogando sua aplicação dos detalhes mais complexos envolvendo multithreading e permitindo que seu código possa se concentrar na lógica de manipulação dos eventos. TÉCNICO EM INFORMÁTICA 1.4. Recursos do Flutter O framework Flutter oferece os seguintes recursos para os desenvolvedores: Um framework moderno e reativo Usa a linguagem de programação Dart que oferece um aprendizado fácil Desenvolvimento rápido Interfaces de Usuário bonitas e fluidas Grande variedade de widgets Roda a mesma aplicação em múltiplas plataformas Aplicações de alta performance 1.5. Vantagens do Flutter Flutter vem com widgets bonitos e customizáveis para alta performance de aplicativos mobile. Ele atende a todas as necessidades e requisitos personalizados. Além disso, o Flutter oferece muito mais vantagens, conforme mencionado abaixo: Dart tem um grande repositório de pacotes de classes os quais permitem ampliar os recursos dos seus aplicativos Desenvolvedores precisam escrever apenas um código base para ser executado tanto no Android como no iOS. O Flutter pode ser ampliado para outras plataformas também no futuro. O Flutter precisa de menos testes, pois sua base de código única possibilita escrevermos testes automatizados válidos para abas as plataformas A simplicidade do Flutter o faz um bom candidato para o desenvolvimento rápido. Sua capacidade de personalização e extensibilidade o tornam ainda mais poderoso. Com Flutter, desenvolvedores tem total controle sobre os widgets e seus layouts. Flutter oferece ótimas ferramentas para desenvolvimento, com a possibilidade de recarregamento em tempo de desenvolvimento. 1.6. Desvantagens do Flutter Apesar de suas muitas vantagens, o Flutter possui as seguintes desvantagens: Uma vez que codificado na linguagem Dart, os desenvolvedores precisam aprender uma nova linguagem (Embora seja fácil aprende-la). Framework moderno tentam separar a lógica da interface do usuário, mas no Flutter a lógica e a interface do usuário são integradas. Podemos superar isso usando uma codificação padronizada usando módulos de alto nível para separar interface do usuário da lógica Flutter é outro framework para criar aplicações mobile. Os desenvolvedores estão tendo dificuldades para escolher ferramentas certas em um segmento tão disputado. TÉCNICO EM INFORMÁTICA 2. Criando uma aplicação no Flutter no VS Code 1. Abra o VSCode 2. Crie um novo projeto Flutter pressionando as teclas Ctrl + Shift + P e clique em Flutter: New Project. TÉCNICO EM INFORMÁTICA 3. Informe o nome do projeto e pressione Enter. O nome do projeto não pode conter letras maiusculas, caracteres especiais e espaços em branco. 4. Selecione o local no qual será criada a pasta do projeto com os arquivos TÉCNICO EM INFORMÁTICA A estrutura básica de uma aplicação no Flutter é a seguinte: .dart_tool - contém o arquivopackage_config.json que controla os pacotes utilizados na aplicação .idea - contém arquivos de configuração do projeto específicos do VS Code android - contém código fonte gerado automaticamente para criar uma aplicação Android ios - contém código fonte gerado automaticamente para criar uma aplicação iOS lib - pasta principal que contém o código Dart utilizado na estrutura do Flutter lib/main.dart - arquivo principal de uma aplicação Flutter test - a pasta contém um código Dart para testar uma aplicação Flutter test/widget_test.dart - código exemplo (pode ser apagado) .gitignore - controle de versão de arquivos do Git .metadata - gerado automaticamente pelas ferramentas do Flutter .packages - gerado automaticamente para controlar os pacotes Flutter iml - arquivo de projeto utilizado pelo VS Code pubspec.yaml - utilizado pelo Pub que é o gerenciador de pacotes do Flutter pubspec.lock - gerado automaticamente pelo Pub que é o gerenciador de pacotes do Flutter README.md - arquivo de descrição do projeto utilizando Markdown format TÉCNICO EM INFORMÁTICA 5. Substitua o código dart no arquivo lib/main.dart com o código abaixo: 1. import 'package:flutter/material.dart'; 2. 3. void main() => runApp(MyApp()); 4. 5. class MyApp extends StatelessWidget { 6. @override 7. Widget build(BuildContext context) { 8. return MaterialApp( 9. title: 'Olá Mundo', 10. theme: ThemeData( 11. primarySwatch: Colors.blue, 12. ), 13. debugShowCheckedModeBanner: false, 14. home: Home(), 15. ); 16. } 17. } 18. 19. class Home extends StatefulWidget { 20. @override 21. _HomeState createState() => _HomeState(); 22. } 23. 24. class _HomeState extends State<Home> { 25. @override 26. Widget build(BuildContext context) { 27. return Scaffold( 28. appBar: AppBar( 29. title: Text("Primeiro App"), 30. centerTitle: true, 31. ), 32. body: Center( 33. child: Text("Olá Mundo"), 34. ), 35. ); 36. } 37. } TÉCNICO EM INFORMÁTICA Vamos entender o código Dart linha a linha Linha 1: importa o pacote Flutter material. O material é um pacote utilizado para criar a interface com o usuário de acordo diretrizes de design especificadas pela Google para o Android. Linha 3: é a inicialização de uma aplicação Flutter. O método main() chama a função runApp e passa como parâmetro a classe MyApp. O objetivo da função runApp é anexar o widget fornecido pela classe MyApp na tela da aplicação. O widget principal de uma aplicação será sempre um MaterialApp. Linhas 5 - 17: O widget é usado para criar uma interface do usuário no framework Flutter. StatelessWidget é um widget que não mantém o estados dos seus widgets filhos. MyApp herda de StatelessWidget e sobrescreve o método build. O propósito do método build é criar uma parte da interface do usuário da aplicação. Aqui o método usa o MaterialApp, um widget para criar a base da interface do usuário da aplicação. Ele tem três propriedades title, theme and home. title: é o título da aplicação theme: é o tema utilizado pelo widget. Aqui, definimos como blue como a cor geral da aplicação usando a classe ThemeData e sua propriedade primarySwatch. home: é a junção de elementos da interface do usuário, que configuramos no outro widget, Home Linhas 19 - 37: Home é um classe que herda StatefulWidget que é um widget que armazena as mudanças de estados dos widgets filhos. A classe Home esta retornando um Scaffold que é um widget de nível superior que junto ao MaterialApp é usado para criar uma interface de usuário conforme as diretrizes do material design. O Scaffold tem duas propriedades importantes, appBar para mostrar o cabeçalho da aplicação e o body que mostra o conteúdo atual da aplicação. AppBar é outro widget que renderiza o cabeçalho da aplicação e que usamos na propriedade appBar. Na propriedade body usamos um widget Center que centraliza o widget filho. O text é o widget filho do Center e apresenta o texto Olá Mundo no centro da tela. 6. Clique no ícone e depois no botão e selecione o device que vai rodar a sua aplicação conforme a figura abaixo TÉCNICO EM INFORMÁTICA 7. A saída da sua aplicação será como a figura abaixo 3. Fundamentos do framework Flutter 3.1. Widgets O conceito central do framework Flutter é que tudo é um widget. Widgets são basicamente componentes de interface de usuário usados para criar a interface da aplicação. Widgets podem ser comparados com blocos Lego; Juntando blocos você pode criar um objeto, e adicionando diferentes tipos de bloco, pode-se alterar a aparência e o comportamento do objeto. Widgets são os blocos de construção de um app Flutter, e cada widget é uma declaração imutável da interface do usuários. Em outras palavras, widgets são configurações (instruções) para partes diferentes da UI. No Flutter a aplicação é um widget de alto nível e seus elementos de interface são construidos usando um ou mais filhos (widgets), os quais novamente usam seus widgets filhos, criando uma árvore de widgets. Por exemplo, digamos que um arquiteto desenha uma planta de uma casa; todos os objetos como paredes janelas e portas na casa são widgets e todos eles funcionam juntos para criar uma casa ou, neste caso a aplicação. Esse recurso de composição nos ajuda a criar uma interface de usuário de qualquer complexidade. TÉCNICO EM INFORMÁTICA Por exemplo, a hierarquia de widget da aplicação ola mundo (criada anteriormente) é a especificada no seguinte diagrama: MyApp é criado pelo usuários e é construido usando widget nativo Flutter, MaterialApp MaterialApp tem uma propriedade home para especificar a interface do usuário da página principal, que é novamente um widget criado pelo usuário, Home. Home é construida usando outro widget nativo do Flutter, Scaffold. Scaffold tem duas propriedades - body e appBar. body é usado para especificar a interface do usuário principal e appBar é usado para especificar o cabeçalho da interface do usuário O cabeçalho da interface do usuário é construido usando o widget nativo Flutter AppBar e body é construido usando o widget Center. O widget Center possui a propriedade child que referencia o conteúdo atual e é construido usando um widget Text. 3.2. Gestos Widgets Flutter suporta interação por meio de um widget especial o GestureDetector, que é um componente não visível que captura as interações do usuário como por exemplo tapping, dragging, entre outras dos seus widgets filhos. Muitos widgets nativos do Flutter suportam interação por meio do uso do GestureDetector. Podemos também incorporar recursos de interatividade em um widget existente com a combinação com o GestureDetector. Em capítulos posteriores o widget GestureDetector será explorado de maneira mais aprofundada. TÉCNICO EM INFORMÁTICA 3.3. Conceito de estados Os widgets Flutter suportam a manutenção de estados fornecendo um widget especial, o StatefulWidget. O widget precisa ser filho do StatefulWidget para suportar a manutenção de estado e os que não necessitam de suporte para manutenção de estado devem ser filhos do StatelessWidget. 3.4. O ciclo de vida do StatefulWidget Um StatefulWidget é construido baseado na sua própria configuração, mas pode mudar dinamicamente. Por exemplo a tela mostra um ícone com uma descrição, mas valores podem mudar baseados na interação do usuário, como escolher um ícone ou descrição diferente. Este tipo de widget tem um estado mutável que pode ser mudar com o tempo. O widget stateful é declarado com duas classes, classe StatefulWidget e a classe State. A classe StatefulWidget é reconstruida quando a configuração do widget muda, mas a classe State pode persistir (permanecer), melhorando o desempenho. Por exemplo quando o estado muda, o widget é reconstruido. Se o StatefulWidget é removido da árvore e então inserido novamente na árvore em algum momento no futuro, um novo estado do objeto é criado. Observe que sob certas circunstâncias e restrições, você pode usar uma GlobalKey (chave exclusiva em todo o app) para reutilizar (não recriar) o estado do objeto; contudoglobal keys são custosas e a menos que sejam necessárias, considere não utilizá-las. Você pode chamar o método setState() para notificar o framework que este objeto mudou e o método build do widget é chamado (agendado). Você deve configurar os novos valores do estado no método setState(). O exemplo seguinte mostra uma estrutura base do StatefulWidget e a Figura ? apresenta o ciclo de vida do widget. Você tem duas classes a ExemploEdit que herda de StatefulWidget e a _ExemploEditState. class ExemploEdit extends StatefulWidget { @override _ExemploEditState createState() => _ExemploEditState(); } class _ExemploEditState extends State<ExemploEdit> { @override Widget build(BuildContext context) { return Container(); } } TÉCNICO EM INFORMÁTICA Figura ?. Ciclo de vida do StatefulWidget Você pode sobrescrever partes diferentes do StatefulWidget para customizar e manipular dados em pontos diferentes do ciclo de vida do widget. A tabela 1 mostra algumas das principais overrides do widget e a maioria das vezes você usará os métodos initState(), didChangeDependencies(), and dispose(). Você usará o método build() todas as vezes para construir sua interface do usuário. TÉCNICO EM INFORMÁTICA Tabela 1: Ciclo de vida do StatefulWidget Método Descrição Código exemplo initState() Chamado uma vez quando esse objeto é inserido na árvore @override void initState() { super.initState(); print('initState'); } dispose() Chamado quando esse objeto é removido da árvore permanentemente @override void dispose() { print('dispose'); super.dispose(); } didChangeDependencies() Chamado quando o estado this do objeto é mudado @override void didChangeDependencies() { super.didChangeDependencies(); print('didChangeDependencies'); } didUpdateWidget- (Contacts oldWidget) Chamado quando a configuração do widget muda @override void didUpdateWidget(Contacts oldWidget) { super.didUpdateWidget(oldWidget); print('didUpdateWidget: $oldWidget'); } deactivate() Chamado quando o objeto é removido da árvore @override void deactivate() { print('deactivate'); super.deactivate(); } build(BuildContext context) Pode ser chamado várias vezes para criar a interface do usuário, e o BuildContext controla a localização desse widget na árvore de widgets. @override Widget build(BuildContext context) { print('build'); return Container(); } setState() Notifica o framework que o estado deste objeto mudou para agendar a chamada de construção para este estado do objeto setState(() { name = _newValue; }); TÉCNICO EM INFORMÁTICA 3.5. O ciclo de vida do StatelessWidget Um StatelessWidget é construido baseado em suas próprias configurações e não muda dinamicamente. Por exemplo, a tela mostra uma imagem com uma descrição e não mudará. O stateless widget é declarado como uma classe. O método build (as partes da interface do usuário) do widget stateless podem ser chamadas de três diferentes cenários. Pode ser chamado na primeira vez que o widget é criado, quando o pai do widget é alterado e quando e quando um widget herdado (InheritedWidget) é alterado. O seguinte código exemplo mostra a estrutura base do StatelessWidget e a Figura ? apresenta o ciclo de vida do widget. class ExemploList extends StatelessWidget { @override Widget build(BuildContext context) { return Container(); } } Figura ?. Ciclo de vida do widget Stateless 3.6. Layers O conceito mais importante do framework Flutter é que o mesmo é agrupado em múltiplas categorias em termos de complexidade e claramente organizado em layers de complexidade decrescente. Um layer é construido sua próxima camada imediata. A camada superior é um widget específico para Android e iOS. O próximo layer tem todos os widgets nativos do Flutter. O próximo nível é o layer de renderização que é o componente renderizador de baixo nível e renderiza todo o aplicativo flutter. Os layers descem para o código específico da plataforma principal. TÉCNICO EM INFORMÁTICA A visão geral de um layer no Flutter é especificado no diagrama abaixo: TÉCNICO EM INFORMÁTICA 4. Introdução a linguagem Dart Dart é uma linguagem de programação open-source de propósito geral. Originalmente desenvolvida pela Google. É uma linguagem orientada a objeto com uma sintaxe C-style sendo utilizada pela Google em alguns de seus maiores produtos como o Google AdWords. Disponibilizada ao público em 2011, Dart é usado para construir aplicações mobile, web e server. Dart é produtivo, rápido, portable e acima de tudo reativa. Se você esta familiarizado com as linguagens C#, C++, Swift, Kotlin, Java e JavaScrip será capaz de começara a desenvolver em Dart rapidamente. Mas não se preocupe, mesmo que você não esteja familiarizado com essas outras linguagens, Dart é uma linguagem simples de aprender, e você pode começar relativamente rápido. Quais são os benefícios de usar o Dart? Em Dart código é transformado de uma só vez antes de atingir as plataformas que o executam, o processo é chamado de Compilação AOT (Ahead-Of-Time). Em outras palavras não intermediários para interpretar de uma linguagem para outra, não havendo pontes. A compilação AOT é usada quando compila seu App para o modo release (como a Apple App Store e o Google Play). Dart também é compilado just-in-time (JIT) tornando mais rápido a exibição das mudanças do seu código utilizando o recurso Flutter stateful hot reload. A compilação (JIT) é usado quando depura seu app rodando em um simulador/emulador. Uma vez que Flutter usar Dart, não existe a necessidade usar linguagens diferentes para criar interface de usuário e a lógica da aplicação. Flutter renderiza de 60 frames por segundo (fps) a 120fps para dispositivos com essa capacidade. Quanto mais fps mais suave o aplicativo. 4.1. Comentando códigos Comentários ajudam a legibilidade do código, desde que não exagere. Comentários podem ser usados para descrever a lógica e as dependências do app. Há três tipos de comentários: linha única, múltiplas linhas e comentários de documentação. Comentários de linha única são normalmente utilizados para adicionar descrições curtas. Comentários de linhas múltiplas são mais adequados para descrições que possuem várias linhas. Comentários de documentação são usados para documentar completamente uma parte do código, geralmente fornecendo explicações detalhadas e exemplos de códigos nos comentários. O comentário com uma única linha inicia com //, e o compilador Dart ignora tudo até o fim da linha. //Este é um comentário de uma única linha Comentários de múltiplas linhas iniciam com /* e terminam com */ e o compilador Dart ignora tudo entre as barras. TÉCNICO EM INFORMÁTICA /*Este é um exemplo de bloco de comentários com múltiplas linhas*/ Os comentários de documentação inicia com ///, e o compilador Dart ignora tudo até o final da linha, a menos que esteja entre colchetes. Usando colchetes você pode consultar classes, métodos, campos, variáveis de nível superior, funções e parâmetros. No exemplo seguinte a documentação gerada, [FilterBy], se torna um link para a documentação da API da classe. Você pode usar a ferramenta de geração de documentação do SDK (dartdoc) para analisar o código Dart e gerar documentação HTML. /// Multiple filter options /// /// Different [FilterBy] enum FilterBy { COMPANY, CITY, STATE } 4.2. Função Main() Todo app deve ter uma função de alto nível main(), que é a inicialização do app. A função main() é onde a execução do app inicia e retorna um void com parâmetro opcional utilizando um objeto List<String>. Cada função pode retornar um valor e para a função main() o valor retornado é do tipo void (vazio, não contém nada) isso significa que não há retorno de valor. No código seguinte, são apresentadas três formas diferentes de usar a função main(). Todas as três formas de chamar a função main() são aceitas, mas por questões de legibilidade do código, por padrão se utiliza a sintaxe de seta void main() => runApp(MyApp()); // sintaxe seta void main() => runApp(MyApp()); // ou voidmain() { runApp(MyApp()); } // ou com uma lista de argumentos string void main(List<Strings> filters) { print('filters: $filters'); } TÉCNICO EM INFORMÁTICA 4.3. Declarando variáveis Na seção anterior você aprendeu que a função main() é a inicialização do app e antes de começar a escrever códigos, é importante aprender sobre variáveis em Dart. Variáveis armazenam referencias a um valor. Alguns tipos de variáveis internas são números, strings, lists, maps entre outros. Você pode usar a palavra reservada var para declarar uma variável sem especificar o tipo. O Dart infere o tipo da variável automaticamente. Contudo não há nada de errado com usar var como uma preferência pessoal. Declarar o tipo de variável facilita a legibilidade do código e é mais fácil saber que tipo de valor é esperado. Ao invés de usar var, use os tipos de variáveis esperados: double, String e assim por diante. Uma variável não inicializada tem um valor null. Quando declara-se uma variável se atribuir um valor inicial, a mesma é chamada de não inicializada. Por exemplo, uma variável do tipo string é declarada como String TituloLivro; e não é inicializada porque TituloLivro tem um valor igual a null (não valor). Contudo se declara-la com um valor inicial String TituloLivro = “Aprendendo Flutter” o valor de TituloLivro é igual a Aprendendo Flutter. Use final ou const quando quiser que o valor inicial da variável são seja modificado. Use const para variáveis que precisam ser tornadas constantes em tempo de compilação, significando que o valor é conhecido em tempo de compilação. Agora que sabe que variáveis armazenam referencias a valores, a seguir aprenderemos opções para declarar variáveis. Em Dart todas variáveis são declaradas públicas (disponível para toda a aplicação) por padrão, mas começar o nome da variável com um underscore (_) torna a variável privada. Declarando uma variável privada, você esta dizendo que a mesma só pode ser acessada na função ou classe na qual foi declarada. Observe que alguns tipos de dados em Dart começam com letra minúscula como double e alguns com letra maiúscula como String. E se o valor de uma variável não precisar mudar? Comece a declaração da variável com as palavras final ou const. Use final quando o valor é atribuído em runtime (pode ser mudado pelo usuário). Use const quando o valor é conhecido em tempo de compilação (no código) e não será mudado em runtime. // Declaração sem especificar o tipo - Inferência de tipo var filtro = “empresa”; // Declarando tipo String filtro = “empresa”; // Variável não inicializada tem um valor null String filtro; // Valor não será mudado final filtro = “empresa”; // ou final String filtro = “empresa”; TÉCNICO EM INFORMÁTICA // ou const String filtro = “empresa”; // ou const String filtro = “empresa” + filterOption; // Variável Pública (o nome da variável sem underscore) String userName = “maria”; // Variável privada (o nome da variável começa com underscore) String _userID = 'XW904'; 4.3.1. Números Declarar variáveis como número restringe os valores aceitos a números somente. O Dart fornece dois tipos numéricos: int (inteiros) e double (reais). Ambos int e double permitem números positivos e negativos e você pode inserir números extremamente grandes e precisão decimal, pois ambos usam valores de 64 bits (memória do computador). // Integer int contador = 0; double preco = 0.0; preco = 125.00; 4.3.2. String Declarar variáveis como String permite valores do tipo cadeia de caracteres. Para adicionar uma única linha de caracteres, pode-se utilizar uma aspas simples ou duplas como ‘carro’ ou “carro”. Para adicionar múltiplas linhas de caracteres use três aspas simples, como ‘’’carro’’’ Strings podem ser concatenadas (combinadas) usando um operador (+) ou usando aspas simples ou duplas adjacentes. // Strings String defaultMenu = 'main'; // Concatenação de String String combinedName = 'main' + ' ' + 'function'; String combinedNameNoPlusSign = 'main' ' ' 'function'; // String multi-line String multilineAddress = ''' 123 Any Street City, State, Zip '''; TÉCNICO EM INFORMÁTICA 4.3.3. Booleano Declarar variáveis como bool (booleana) permite um valor lógico true (verdadeiro) ou false (falso) // Booleans bool isDone = false; isDone = true; 4.3.4. List Declarando variáveis como List (pode ser comparada como um array) permite que múltiplos valores sejam informados para a mesma variável. E se caracteriza como um grupo ordenado de objetos. Em programação um array é uma coleção iterável (acessada sequencialmente) de objetos, com cada elemento sendo acessado por um índice de posição ou uma chave (key) Para acessar elementos o List usa como posição inicial o índice 0 e o ultimo elemento é o tamanho do List menos 1 (uma vez que o primeiro elemento do List esta na posição 0 e não 1). Um List poder tem o tamanho fixado ou dinâmico, dependendo da necessidade. Por padrão, um List é criado como dinâmica usando List() ou [ ]. Para criar um List de tamanho fixo adiciona-se o número de posições que se deseja, usando este formato: List(25). O exemplo a seguir utiliza a interpolação de String na instrução print: print('filtro: $filtro') // List dinânica List contatos = List(); // or List contatos = []; List contatos = ['Linda', 'John', 'Mary']; // List de tamanho fixo List contato = List(25); // Lists - Em Dart um List é um array List listOfFilters = ['company', 'city', 'state']; listOfFilters.forEach((filter) { print('filter: $filter'); }); // Resultado da instrução print // filter: company // filter: city // filter: state TÉCNICO EM INFORMÁTICA 4.3.5. Maps Maps são listas compostas de chave e valor que permitem recuperar valores pelo o ID da chave. A chave e o valor podem ser qualquer tipo de objeto, como String, números, entre outros. Tenha em mente que a chave precisa ser única uma vez que o valor é recuperado pelo ID da chave. // Maps - Um objeto que associa chaves e valores. // Key: IDvalor - 'KeyValue': 'Valor' Map mapFiltros = {'id1': 'compania', 'id2': 'cidade', 'id3': 'estado'}; // Mudar o valor da item com a chave id3 mapFiltros['id3'] = 'meu filtro'; print('Obtenha o fitro com id3: ${mapFiltros['id3']}'); // Resultado da instrução print // Obtenha o fitro com id3: meu filtro 4.3.6. Runes Em Dart declarar uma variável como Runes da suporte a códigos Unicode UTF-32. Unicode define um valor numérico para cada letra, caractere especial e símbolos. O Dart usa a sequencia de unidades de código UTF-16 para representar um valor Unicode UTF-32 a partir de uma sintaxe especial requerida de String (\uXXXX). \uXXXX é um exemplo de código Unicode no qual XXXX é um valor hexadecimal de quatro dígitos. Runes retorna um valor inteiro do código Unicode; então você usa String.fromCharCodes() para alocar uma nova String para charCode especificado. // Para o emoji anjo sorridente Unicode é u+1f607 // Remova o sinal de mais e abra uma chave antes do número e a feche após Runes meuEmoji = Runes('\u{1f607}'); print(meuEmoji); // Resultado da instrução print // (128519) print(String.fromCharCodes(meuEmoji)); // resultado // x TÉCNICO EM INFORMÁTICA 4.4. Usando operadores Um operador é um símbolo usado para executar operações aritméticas, lógicas, relacionais, teste de tipo, atribuição e condicional lógica. As tabelas de 2 a 8 apresentam os operadores comuns de cada categoria. Como exemplo foram usados valores literais ao invés de variável para simplificar a escrita. Tabela 2: Operadores aritméticos Operador Descrição Código exemplo + Adição 7 + 3 = 10 - Subtração 7 - 3 = 4 * Multiplicação 7 * 3 = 21 / Divisão 7 / 3 = 2.33 Tabela 3: Operadores relacionais Operador Descrição Código exemplo == Igual 7 == 3 = false != Diferente 7 != 3 = true > Maior que 7 > 3 = true < Menor que 7 < 3 = false >= Maior ou igual 7 >= 3 = true 4 >= 4 true <= Menor ou igual 7<= 3 = false 4 <= 4 = true Tabela 4: Operadores de testes de tipo Operador Descrição Código exemplo as Usado para criar um alias na importaçãode bibliotecas Import 'travelpoints.dart' as travel; is Se o objeto contém o tipo específico é retornado true if (points is Places) = true is! Se o objeto contém o tipo específico é retornado false (Não é normalmente usado) 7 * 3 = 21 Tabela 5: Operador ternário Operador Descrição Código exemplo condição ? valorTrue : valorFalse Se a condição avaliada retornar true, o retorno é o valorTrue. Se a condição avaliada retornar false o valorFalse é retornado (7 > 3) ? true : false = true (7 < 3) ? true : false = false TÉCNICO EM INFORMÁTICA Tabela 6: Operadores de atribuição Operador Descrição Código exemplo = Atribuição de valores 7 = 3 = 3 ??= Atribui o valor somente se a variável que está sendo avaliada tem um valor null Null ??= 3 = 3 7 ??= 3 = 7 += Adiciona o valor indicado a variável 7 += 3 = 10 -= Subtrai o valor indicado da variável 7 -= 3 = 4 *= Multiplica o valor indicado pela variável 7 *= 3 = 21 /= Divide a variável pelo valor indicado 7 /= 3 = 2.33 Tabela 7: Operadores lógicos Operador Descrição Código exemplo ! É o operador lógico ‘not’. Retorna o valor oposto da variável/expressão if (!(7 > 3)) = false && && é o operador lógico ‘and’. Retorna true se todos os valores das expressões/variáveis forem verdadeiros if ( (7 > 3) && (3 < 7) ) = true if ( (7 > 3) && (3 > 7) ) = false !! !! é o operador lógico ‘or’. Retorna true se pelo menos um dos valores das expressões/variáveis forem verdadeiros if ( (7 > 3) || (3 > 7) ) = true if ( (7 < 3) || (3 > 7) ) = false Tabela 8: Notação em cascata Operador Descrição Código exemplo ! A notação em cascata é representado por dois pontos(..) e permite efetuar uma sequencia de operações no mesmo objeto if (!(7 > 3)) = false TÉCNICO EM INFORMÁTICA 4.5. Usando instruções de controle de fluxo Para controlar o fluxo lógico no código Dart observe as seguintes instruções de fluxo: if e else são as instruções de fluxo mais comuns; Elas decidem que trecho de código será executado com base na análise de expressões condicionais. O operador ternário é similar as instruções if e else, mas é usado somente quando há somente a análise de uma condição. O loop for permite a iteração em uma lista de valores. while e do-while são uma dupla comum. Use o loop while para avaliar a condição antes de inicializar o loop e use do-while para avaliar a condição depois da execução de uma iteração do loop. while e break são úteis se você precisa parar a avaliação da condição no loop. continue é para quando você precisa parar a iteração corrente e inicializar o próximo ciclo de iteração. switch e case são alternativas para as instruções if e else, mas requer uma clausula default. 4.5.1. if e else A instrução if analisa uma expressão lógica e se o retorno desta expressão for true (verdadeiro) o bloco de instruções associadas ao if é executado. A expressão lógica é envolvida por parênteses (expressão lógica) e o bloco de instruções envolvido por chaves {conjunto de instruções}. O if também suporta a instrução else que é contém o bloco de instruções que serão executados se a condição lógica analisada retornar false (falso). Também é possível utilizar múltiplas instruções else if em um em um bloco if, mas somente um else para fechar o bloco condicional. No exemplo seguinte verifica a situação de um aluno em uma matéria. Primeiro a instrução if verifica se a nota é menor igual a 5, se a analise retornar true é apresentada e mensagem Reprovado. Se for retornado false será executada a próxima verificação associada ao else if, se a nota é igual a 10 se o retorno for true será apresentada a mensagem Aprovado com louvor senão será apresentada a mensagem Aprovado double nota = 7.0; if(nota <= 5.0){ print("Reprovado"); } else if (nota == 10.0) { print("Aprovado com louvor"); } else { print("Aprovado"); } TÉCNICO EM INFORMÁTICA 4.5.2. Operador ternário O operador ternário recebe três argumentos e é normalmente usado quando somente duas ações são necessárias. O primeiro argumento é a expressão lógica a ser analisada, o segundo é a instrução a ser executada se o retorno da expressão for true e o terceiro é a instrução a ser executada se o retorno da expressão for false. EXPRESSÃO LÓGICA TRUE FALSE nota >= 5.0 ? print("Aprovado") : print("Reprovado") 4.5.3. switch - case A instrução switch avalia o valor de uma variável inteira ou string comparando com os valores apresentados nas clausulas case. Se o valor armazenado na variável for compatível com algum case, o conjunto de instruções associados ao mesmo é executado. Se não houver nenhum case compatível é executado o bloco de instruções associados a clausula default. As seguintes regras se aplicam a instrução switch: Pode haver qualquer número de clausulas case em um switch; As clausulas case podem utilizar somente valores constantes. Não pode ser usadas variáveis ou expressões lógicas; O tipo de dados da variável utilizado nas clausulas case tem que ser o mesmo da variável analisado pelo switch; Se não colocar a instrução break em cada bloco o fluxo de execução continuará mesmo que a opção correta tenha sido encontrada. Cada clausula case deve ter um valor único; A clausula default é opcional. TÉCNICO EM INFORMÁTICA Exemplo switch…case void main() { var nota = "A"; switch(nota) { case "A": print("Excelente"); print("Aprovado"); break; case "B": print("Bom"); print("Aprovado"); break; case "C": print("Regular"); print("Aprovado"); break; case "D": print("Insatisfatório"); print("Reprovado"); break; case "E": print("Insatisfatório"); print("Reprovado"); break; default: print("Nota inválida"); break; } } TÉCNICO EM INFORMÁTICA 4.5.4. Loop for A instrução for permite a iteração com uma lista de valores. Os valores são obtidos restringindo o número de iterações pelo tamanho do objeto list. Outra forma de execução é determinar um valor inicial, um valor final e um valor de passo para o loop for. Usar uma lista de valores também permite o uso do for-in como uma iteração. A classe Iteration precisa ser do tipo Iterável (uma coleção de valores), e a classe List é deste tipo. Ao contrário do loop for padrão o for-in itera por todos os objetos do List, expondo os valores de propriedades de cada objeto. Vamos dar uma olhada em dois exemplos mostrando como usar o loop for padrão e o loop for-in. No primeiro exemplo, será utilizado o loop for padrão iterando em um list de valores string com a variável listaFiltros. O loop for padrão recebe três parâmetros. O primeiro parâmetro inicializa a variável do tipo int aqui chamada de i que contará cada execução do loop. O segundo parâmetro controla quantas iterações serão executadas pelo loop. Para esse controle executa-se a comparação do valor atual de (i) como o número total de iterações a serem executadas. Uma vez que o índice do list inicia em zero a variável i tem que ter um valor menor que o tamanho do list. Para se obter o número correto de iterações usa-se o tamanho do list (listaFiltros.length) - 1. O terceiro parâmetro incrementa o número de iterações executada pelo acréscimo da variável i a cada loop. Dentro do loop a instrução print é utilizada para mostrar cada valor do list listaFiltros. // Loop for padrão List listaFiltros = ['compania', 'cidade', 'estado']; for (int i = 0; i < listaFiltros.length; i++) { print('listaFiltros: ${listaFiltros[i]}'); } // resultado da instrução print // listaFiltros: compania // listaFiltros: cidade // listaFiltros: estado No exemplo a seguir será utilizado o loop for-in para iterar com valores da variável list listaNumeros a qual possui uma lista de números inteiros. O loop for-in recebe um parâmetro que apresenta as propriedade do objeto listaNumeros. Foi declarada uma variável do tipo int numero para acessar as propriedade do objeto List listaNumeros. No interior do loop, a instrução print é usada para mostrar cada valor da listaNumeros utilizando o valor da variável numero. TÉCNICO EM INFORMÁTICA // loop for-inList listaNumberos = [10, 20, 30]; for (int numero in listaNumberos) { print('número: $numero'); } // Resultado da instrução print // número: 10 // número: 20 // número: 30 4.5.5. Loop while e do-while Ambos os loops while e do-while avaliam uma condição e executam iterações enquanto a condição retorna um valor true. O loop while avalia a condição antes da iteração ser executada. Já o loop do-while avalia a condição depois que a iteração é executada pelo menos uma vez. Vamos observar dois exemplos que mostram como usar os loops while e do-while. O primeiro exemplo funciona da seguinte forma, enquanto a condição definida for verdadeira, o conjunto de instruções do loop é executado. Geralmente é utilizado quando não se sabe quantas vezes irá repetir o conjunto de instruções. int j = 0; bool sair = “n”; while(j < 10){ print(j); // Mostra de 0 a 9 j++; } No segundo, diferente do while que avalia a condição antes do loop, o do-while executa o conjunto de instruções do loop e depois avalia a condição. Se a analise retornar true é iniciada uma nova iteração. Este ciclo se repete até que a avaliação da condição se torne false. int k = 0; do { print(k); k++; } while (k < 10); TÉCNICO EM INFORMÁTICA 4.5.6. while e break Usar a instrução break permite parar um loop pela avaliação de uma condição na iteração. var i = 1; while (i <= 10) { if (i % 5 == 0) { print("O primeiro multiplo de 5 entre 1 e 10 é : ${i}"); break; //sai do loop quando o primeiro múltiplo é encontrado } i++; } 4.5.7. continue Usando a instrução continue, é possível parar no local atual da iteração e pular para o início do próxima iteração do loop. No exemplo o loop for percorre uma lista de números de 10 a 80. Dentro do loop uma instrução if verifica quando o número é menor que 30 e maior que 50, e se a condição é encontrada, a instrução continue para a iteração corrente e começa a próxima. Usando a instrução print, será apresentado somente os número 30, 40 e 50. // Continue - pula para a próxima iteração do loop List listaNumeros = [10, 20, 30, 40, 50, 60, 70, 80]; for (int numero in listaNumeros) { if (numero < 30 || numero > 50) { continue; } print('nmero: $numero'); // Serão apresentados os números 30, 40, 50 } 4.6. Usando funções Funções são usadas para agrupar trechos de código que serão utilizados em vários pontos da programação. Uma função pode opcionalmente receber parâmetros e retornar valores. Em razão do Dart ser uma linguagem orientado a objeto, funções podem ser atribuídas a variáveis ou passadas como argumento para outras funções. Se um função executa uma única instrução, pode-se utilizar a sintaxe seta (=>). Toda função retorna um valor padrão e se a instrução return não é especificada, o Dart automaticamente adiciona implicitamente no corpo da função uma instrução return null. Uma vez que toda função retorna um valor, inicia-se a construção com a especificação do tipo de retorno que é esperado. Quando chama a função e nenhum valor de retorno é esperado, inicie a declaração da função o tipo void que significa nenhum retorno. Usar o tipo void na declaração da função não é obrigatório em Dart já que a linguagem faz isso implicitamente quando uma função não tem retorno, mas é recomendada a pratica de declarar o void por uma questão de legibilidade de código. Mas quando TÉCNICO EM INFORMÁTICA é esperado um retorno de um valor inicie a declaração da função com o tipo de dado que será retornado (bool, int, String, List. . .) e use a instrução return para retornar o valor. Sintaxe TipoDeRetorno nomeDaFuncao(TipoDoArgumento nomeDoArgumento, OutroTipo outroNomeDeArgumento){ // Aqui vai o corpo da função return tipoDeRetorn; } Exemplos void main() { int multiplicacao(int valor1, int valor2) { return (valor1 * valor2); } print(multiplicacao(4, 3)); } Quando se tem uma função com uma única instrução pode-se declara-la utilizando a sintaxe de seta void main() { int multiplicacao(int valor1, int valor2) => (valor1 * valor2); print(multiplicacao(2, 3)); } Quando se tem uma função que somente chama outra função pode-se utiliza a sintaxe de seta para a chamada. void multiplicacao(int valor1, int valor2) => print(valor1 * valor2); void main() => multiplicacao(10, 3); Algumas vezes criamos funções que podem ou não precisar de alguns argumentos e em Dart você pode definir que os argumentos podem ser opcionais e se necessário definir valores padrão para o argumento caso nenhum valor seja definido na chamada da função. Tem duas formas de fazer isso: 4.6.1. Parâmetros nomeados opcional Como o nome sugere, os parâmetros tem nomes e para passar algum valor para o parâmetro nomeado que é opcional é preciso indicar para qual parâmetro é aquele valor e a sintaxe é muito simples nomeDoParam: valor, outroParam: outroValor TÉCNICO EM INFORMÁTICA Exemplo void exemploParametroNomeadoOpcional (String msg/*Parâmetro obrigatorio*/,{String nome, String sobrenome /*Parâmetros opcionais*/}){ print('$nome $sobrenome: $msg'); } main(){ exemploParametroNomeadoOpcional("Olá viajante!"); exemploParametroNomeadoOpcional("Olá!", nome: "João", sobrenome: "da Silva"); exemploParametroNomeadoOpcional("Olá!", sobrenome: "Maria", nome: "José"); } 4.6.2. Parâmetros posicionados opcional Muito parecido com os parâmetros nomeados que você pode declarar em qualquer ordem desde que indique o nome do parâmetro que o valor será atribuído, os parâmetros posicionados tem que seguir a ordem exata que foram declarados na função. Exemplo void funcaoParametroPosicionadoOpcional (String msg/*Parâmetro obrigatorio*/,[String nome, String sobrenome /*Parâmetros opcionais*/]){ print('$nome $sobrenome: $msg'); } main(){ funcaoParametroPosicionadoOpcional("Olá viajante!"); funcaoParametroPosicionadoOpcional("Olá!", "Wilton","Jr"); } 4.6.3. A função main Você deve ter reparados em alguns exemplos o uso da função main(){} ela é o ponto de partida quando um app ou um script Dart é executado. A função main ela retorna nulo e pode receber uma lista de String como parâmetro para quando você for usar o cmd ou terminal para executar algum app/script Dart o que for digitado vai ser passado como List<String> a partir dai é só tratar cada String . main(List<String> args){ print(args) } TÉCNICO EM INFORMÁTICA 4.7. Importação de pacotes Para usar um pacote externo, biblioteca ou uma classe externa, usa-se a instrução import. A separação da lógica do código em diferentes arquivos de classe permite que você separe e agrupe o código em objetos gerenciáveis. A instrução import permite o acesso a pacotes, classes e bibliotecas externas. Necessita somente um argumento que especifica a uniform resource identifier (URI) ou em português identificador uniforme de recurso da classe ou biblioteca. Se a biblioteca é criada pelo gerenciador de pacotes então é necessário especificar a diretiva “package:” antes do URI. Ao importar uma classe, você especifica o local e o nome da classe ou package: diretiva. // Importando o pacote material import 'package:flutter/material.dart'; // Importando um classe externa import 'charts.dart'; // Importando uma classe externa de uma pasta diferente import 'services/charts_api.dart'; // Importando uma classe externa com package: diretiva import 'package:project_name/services/charts_api.dart'; 4.8. Usando Classes Dart é uma linguagem orientada a objetos com classes e herança baseada em mixin. Todo objeto é uma instância de uma classe e todas descendem de Object. A herança baseada em mixin significa que, embora toda classe (exceto Object) tenha exatamente uma superclasse, um corpo de classe pode ser reutilizado em várias hierarquias de classe. Os métodos são uma maneira de adicionar funcionalidade a uma classe sem alterar a classe ou criar uma subclasse. TÉCNICO EM INFORMÁTICA 4.8.1. Usando membros da classe Os objetos têm membros que consistem em funções e dados (métodos e variáveis de instância , respectivamente). Quando você chama um método, invoca-o em um objeto: o métodotem acesso às funções e dados desse objeto. Use um ponto ( .) para se referir a uma variável ou método de instância: class Pessoa { String nome; int idade; double altura; void dormir(){ print("$nome está dormindo"); } void aniver(){ idade++; } } void main(){ Pessoa pessoa1 = new Pessoa(); pessoa1.nome = "Diego"; pessoa1.altura = 1.70; pessoa1.idade = 30; print(pessoa1.nome); pessoa1.aniver(); print(pessoa1.idade); } 4.8.2. Usando construtores Pode-se criar um objeto usando construtor. O nome do construtor pode ser o nomeClasse() ou nomeClasse.Identificador(). No primeiro exemplo é criada uma classe Pessoa que utiliza o construtor Pessoa(), já no segundo exemplo utiliza-se o construtor Pessoa.individuo() TÉCNICO EM INFORMÁTICA Exemplo 1. class Pessoa { String nome; int idade; double altura; Pessoa(this.nome, this.altura, this.idade); void dormir(){ print("$nome está dormindo"); } void aniver(){ idade++; } } void main() { var pessoa = Pessoa("João", 1.80, 33); pessoa.dormir(); } Exemplo 2. class Pessoa { String nome; int idade; double altura; Pessoa.individuo(this.nome, this.altura, this.idade); void dormir(){ print("$nome está dormindo"); } void aniver(){ idade++; } } void main() { var pessoa = Pessoa.individuo("João", 1.80, 33); pessoa.dormir(); } TÉCNICO EM INFORMÁTICA 4.8.3. Herança Dart possui herança simples class Animal { String nome; double peso; Animal(this.nome, this.peso); void comer() { print("$nome comeu"); } void fazerSom() { print("$nome fez dom!"); } } class Cachorro extends Animal { int fofura; Cachorro(this.fofura, String nome, double peso) : super(nome, peso); void brincar() { fofura += 10; print("fofura do $nome aumentou para $fofura"); } } class Gato extends Animal { Gato(String nome, double peso) : super(nome, peso); bool estaAmigavel() { return true; } } TÉCNICO EM INFORMÁTICA 4.8.4. Mixins Os Mixins permitem com que você adicione métodos de outras classes em sua classe sem utilizar herança. Vamos criar uma classe para podermos entender melhor: void main(){ Carro c1 = Carro("Fusca"); c1.acelerar(100); } class Carro extends Automovel { String nome; Carro(this.nome); void acelerar(int velocidade) { print("Acelerando com $velocidade km/h"); } String toString(){ return nome; } } abstract class Automovel { void acelerar(int velocidade); } Agora vamos criar outra classe Combustível em que iremos criar um método abastecer: class Combustivel{ abastacer(int qtde){ print("Abastecendo $qtde l") } } TÉCNICO EM INFORMÁTICA Como a classe Carro já foi herdada de automóvel, não pode ser herdada da classe de Combustível então vamos utilizar o mixin: class Carro extends Automovel with Combustivel { String nome; Carro(this.nome); void acelerar(int velocidade) { print("Acelerando com $velocidade km/h"); } String toString(){ return nome; } } class Combustivel{ abastacer(int qtde){ print("Abastecendo $qtde l") } } abstract class Automovel { void acelerar(int velocidade); } É como se o método abastecer fosse copiado para dentro da classe Carro. Sendo assim, podemos agora incluir em main o método que fora adicionado: void main(){ Carro c1 = Carro("Fusca"); c1.acelerar(100); c1.abastecer(50); } Agora está tudo funcionando, porém, caso você queira acrescentar mais classes, você pode utilizar uma vírgula e acrescentar a nova classe posteriormente: class Carro extends Automovel with Combustivel, B, C, D { String nome; Carro(this.nome); void acelerar(int velocidade) { print("Acelerando com $velocidade km/h"); } String toString(){ return nome; } } TÉCNICO EM INFORMÁTICA 4.8.5. Classes Abstratas Não é concreta, é só uma ideia, um conceito abstrato, uma classe genérica só tem um conteúdo padrão que depois poderá ser implementado de uma forma concreta. Por exemplo, dentro de Animal temos os felinos e pessoas, dentro de felinos gato e tigre que são concretos. Assim, vemos que as classes abstratas são genéricas. Usamos a palavra chave abstract para impedir que uma classe possa ser instanciada. Esse é o efeito direto de se usar o modificador abstract na declaração de uma classe: abstract class Animal { String nome; double peso; Animal(this.nome, this.peso); void comer(){ print("$nome comeu"); } void fazerSom(){ print("$nome fez som!"); } } Pode-se também declarar métodos nas classes abstratas sem declarar nada, sem nenhum corpo, ou seja, na parte void fazerSom() pode-se retirar o seu corpo, desta forma: abstract class Animal { String nome; double peso; Animal(this.nome, this.peso); void comer(){ print("$nome comeu"); } void fazerSom(); } TÉCNICO EM INFORMÁTICA E sempre que herda-las temos que implementar o método: abstract class Animal { String nome; double peso; Animal(this.nome, this.peso); void comer(){ print("$nome comeu"); } void fazerSom(); } class Gato extends Animal { Gato(String nome, double peso): super(nome, peso); bool estaAmigavel(){ return true; } // Obrigado a implementá-lo @override void fazerSom(){ print("$nome fez miau!"); } } Agora vamos em declarar em main para ver o que ocorre: main() { var gato = Gato('Garfield', 0.30); gato.fazerSom(); } Irá mostrar 'Garfield fez miau!' no console, veja que implementamos o método fazerSom() da classe abstrata no Gato. TÉCNICO EM INFORMÁTICA 4.8.6. Interfaces As interfaces definem um conjunto de métodos disponíveis em um objeto. O Dart não possui uma sintaxe para declarar interfaces. As próprias declarações de classe são interfaces no Dart. As classes devem usar a palavra-chave implements para poder usar uma interface. Quando qualquer classe implementa uma Interface, ela deve redefinir todos os métodos e variáveis de instância da interface. void main() { Pais br = new Pais(); print("Nome país : ${br.nome()}"); } class Pais implements PaisInfo { String nome() { return "Brasil"; } String bandeira() { return "Verde Amarelo"; } } class PaisInfo { String nome(){} String bandeira(){} } Dart não suporta múltiplas heranças, mas pode implementar múltiplas interfaces. Tal recurso fornece o mesmo poder e funcionalidades da múltipla herança. class nome implements interface1, interface2, interface3 TÉCNICO EM INFORMÁTICA 5. Criando AlertDialogs Uma caixa de diálogo de alerta, AlertDialgos, informa o usuário sobre situações que exigem reconhecimento. Um diálogo de alerta tem um título opcional e uma lista opcional de ações onde o título é exibido acima do conteúdo e as ações são exibidas abaixo do conteúdo. Ele aparece como um pop-up no meio da tela que coloca uma sobreposição sobre o fundo. É mais usado para confirmar uma das ações irreversíveis do usuário. A maneira mais simples de criar um diálogo de alerta é chamar a função showDialog() que altera o estado da aplicação. Assim temos que definir a função showDialog() com um context e uma função itemBuilder que precisa retornar um objeto do tipo Dialog, onde a opção mais comum é usar um AlertDialog. void _exibirDialogo() { showDialog( context: context, builder: (BuildContext context) { return AlertDialog(); }, ); } Podemos ter muitas configurações para um AlertDialog, onde vários atributos podem ser definidos incluindo o titulo contéudo e Actions ou ações. A Actions é o lugar onde você define os Buttons, geralmente na parte inferior da caixa de diálogo. A seguir um trecho de código básico para definição de um AlertDialog com um botão: void _showDialog() { showDialog( context: context, builder: (BuildContext context) { // retorna um objeto do tipo Dialog return AlertDialog( title: new Text("Alert Dialog titulo"), content: new Text("Alert Dialog body"), actions: <Widget>[ // define os botões na base do dialogo new FlatButton( child: new Text("Fechar"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); TÉCNICO EM INFORMÁTICA 5.1. Criando AlertDialogs 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_alertdialogs e tecle ENTER.Na janela de diálogo a seguir selecione a pasta onde o projeto vai ser salvo e clique em: Select a folder to create the project in. O Flutter vai criar um projeto padrão onde todo o código da aplicação vai estar no arquivo main.dart dentro da pasta lib do projeto. TÉCNICO EM INFORMÁTICA Vamos substituir o código do arquivo main.dart pelo código abaixo: import 'package:flutter/material.dart'; import 'AlertDialogs/alerts.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'AlertDialog', theme: ThemeData( primarySwatch: Colors.blue, ), debugShowCheckedModeBanner: false, home: Home(), ); } } class Home extends StatefulWidget { @override _HomeState createState() => _HomeState(); } class _HomeState extends State<Home> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Alert Dialog"), centerTitle: true, ), body: Padding( padding: const EdgeInsets.all(8.0), child: RaisedButton( child: Text('Exibir Alerta'), onPressed: () { showAlertDialog1(context); }, ), ), ); } } Este será o nosso template onde temos um botão com o texto 'Exibir Alerta' que ao ser clicado aciona o método onPressed() e chama o método showAlertDialog1(context) onde vamos definir o código para criar os AlertDialog. Dentro da pasta lib do projeto, clique com o botão direito do mouse e crie uma pasta chamada AlertDialogs e nesta nova, pasta clique com o botão direito do mouse e crie o arquivo alerts.dart para definir o código de cada um dos AlertDialogs. TÉCNICO EM INFORMÁTICA 5.1.1. Criando uma caixa de alerta com um botão import 'package:flutter/material.dart'; showAlertDialog1(BuildContext context) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text("Promoção Imperdível"), content: Text("Não perca a promoção."), actions: [ FlatButton( child: Text("OK"), onPressed: () { // fecha o AlertDialog Navigator.of(context).pop(); }, ), ], ); }, ); } TÉCNICO EM INFORMÁTICA 5.1.2. Criando uma caixa de alerta com dois botões showAlertDialog2(BuildContext context) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text("Alert Dialog"), content: Text("Deseja continuar aprendendo Flutter ?"), actions: [ FlatButton( child: Text("Cancelar"), onPressed: () { // fecha o AlertDialog Navigator.of(context).pop(); }, ), FlatButton( child: Text("Continar"), onPressed: () { // fecha o AlertDialog Navigator.of(context).pop(); }, ), ], ); }, ); } TÉCNICO EM INFORMÁTICA 5.1.3. Criando uma caixa de alerta com três botões showAlertDialog3(BuildContext context) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text("Aviso"), content: Text("Disparar este míssil vai destruir o mundo."), actions: [ FlatButton( child: Text("Lembrar"), onPressed: () { // fecha o AlertDialog Navigator.of(context).pop(); }, ), FlatButton( child: Text("Cancelar"), onPressed: () { // fecha o AlertDialog Navigator.of(context).pop(); }, ), FlatButton( child: Text("Disparar"), onPressed: () { // fecha o AlertDialog Navigator.of(context).pop(); }, ), ], ); }, ); } TÉCNICO EM INFORMÁTICA 5.2. RFlutter Alert RFlutter Alert é alert/popup dialog customizável fácil de usar para Flutter. Você pode criar estilos de alerta reutilizáveis ou adicionar botões quantas vezes quiser com facilidade 5.2.1. Recursos Uma linha básica para criação do alert Adição de botões dinamicamente Estilos de Alertas pré definidos (success, error, warning, info) Estilos de Alertas reutilizáveis Personalizável: Mudança de animação (fromTop, fromBottom, fromRight, fromLeft, grow, shrink) Configuração de tempo de animação Show/hide close button Definir toque de sobreposição para ignorar Atribuir estilos de título e descrição Alterar o estilo da borda da caixa de diálogo 5.2.2. Iniciando Você deve adicionar a biblioteca como uma dependência no seu projeto no arquivo pubspec.yaml dependencies: rflutter_alert: ^1.0.3 Também é possível referenciar o repositório git se quiser: dependencies: rflutter_alert: git: git://github.com/RatelHub/rflutter_alert.git Depois de adicionar as dependências deve-se executar o comando: flutter packages get E no arquivo arquivo de implementação dos alerts deve-se fazer a importação do pacote: import 'package:rflutter_alert/rflutter_alert.dart'; TÉCNICO EM INFORMÁTICA 5.2.3. Exemplo RFlutter Alert 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 : alert_rflutter e tecle ENTER. Na janela de diálogo a seguir selecione a pasta onde o projeto vai ser salvo e clique em: Select a folder to create the project in. O Flutter vai criar um projeto padrão onde todo o código da aplicação vai estar no arquivo main.dart dentro da pasta lib do projeto. TÉCNICO EM INFORMÁTICA Vamos substituir o código do arquivo main.dart pelo código abaixo: import 'package:flutter/material.dart'; import 'package:alert_rflutter/alert/alerts.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'AlertDialog', theme: ThemeData( primarySwatch: Colors.blue, ), debugShowCheckedModeBanner: false, home: Home(), ); } } class Home extends StatefulWidget { @override _HomeState createState() => _HomeState(); } class _HomeState extends State<Home> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Alert Dialog"), centerTitle: true, ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RaisedButton( child: Text('Alert Básico'), onPressed: () => onBasicAlertPressed(context), ), RaisedButton( child: Text('Alert com Botão'), onPressed: () => onAlertButtonPressed(context), ), RaisedButton( child: Text('Alert com vários Botões'), onPressed: () => onAlertButtonsPressed(context), ), RaisedButton( child: Text('Alert utilizando Estilos'), onPressed: () => onAlertWithStylePressed(context), ), RaisedButton( child: Text('Alert com imagem personalizada'), onPressed: () => onAlertWithCustomImagePressed(context), ), RaisedButton( child: Text('Alert com conteúdo personalizado'), onPressed: () => onAlertWithCustomContentPressed(context), ), ], ), ) ); } } TÉCNICO EM INFORMÁTICA Este será o nosso template no qual temos vários botões que ao serem clicados acionam os seus métodos onPressed() e chamam o método associados a cada um deles. Neste métodos vamos definir o código para criar os AlertDialog. Dentro da pasta lib do projeto, clique com o botão direito do mouse e crie uma pasta chamada alert e nesta nova pasta vamos criar o arquivo alerts.dart para definir o código de cada um dos AlertDialogs. Também criaremos uma pasta assets na raiz do projeto. E nesta pasta coloque o arquivo success.png. TÉCNICO EM INFORMÁTICA Para usar um recurso como fontes e imagens é necessário inserir o mesmo no pubspec.yaml para que a aplicação tenha acesso ao recurso. Para isso abra arquivo pubspec.yaml para inserir o recurso de imagem No arquivo alerts.dart insira o seguinte código: import 'package:flutter/material.dart'; import 'package:rflutter_alert/rflutter_alert.dart'; Estes imports possibilitam o uso dos recursos da biblioteca material e da rflutter_alert. A seguir serão apresentados os trechos de códigos com a imagem dos alert criado. 5.2.4. A maneira mais fácil de criar o alerta com RFlutter onBasicAlertPressed(context) { Alert( context: context, title: "RFLUTTER ALERT", desc: "Flutter é mais impressionante com o RFlutter Alert.") .show(); } TÉCNICO EM INFORMÁTICA 5.2.5. Alert com único botão com RFlutter onAlertButtonPressed(context) { Alert( context: context, type: AlertType.error, title: "RFLUTTER ALERT", desc: "Flutter é mais impressionante com o RFlutter Alert.",buttons: [ DialogButton( child: Text( "LINDO", style: TextStyle(color: Colors.white, fontSize: 20), ), onPressed: () => Navigator.pop(context), width: 120, ) ], ).show(); } 5.2.6. Alert com vários botões customizados RFlutter onAlertButtonsPressed(context) { Alert( context: context, type: AlertType.warning, title: "RFLUTTER ALERT", desc: "Flutter é mais impressionante com o RFlutter Alert.", buttons: [ DialogButton( child: Text( "FLAT", style: TextStyle(color: Colors.white, fontSize: 20), ), onPressed: () => Navigator.pop(context), color: Color.fromRGBO(0, 179, 134, 1.0), ), DialogButton( child: Text( "GRADIENT", style: TextStyle(color: Colors.white, fontSize: 20), ), onPressed: () => Navigator.pop(context), gradient: LinearGradient(colors: [ Color.fromRGBO(116, 116, 191, 1.0), Color.fromRGBO(52, 138, 199, 1.0) ]), ) ], ).show(); } TÉCNICO EM INFORMÁTICA 5.2.7. Uso avançado de alerts onAlertWithStylePressed(context) { // Estilo de alerta personalizado e reutilizável var alertStyle = AlertStyle( animationType: AnimationType.fromTop, isCloseButton: false, isOverlayTapDismiss: false, descStyle: TextStyle(fontWeight: FontWeight.bold), animationDuration: Duration(milliseconds: 400), alertBorder: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0.0), side: BorderSide( color: Colors.grey, ), ), titleStyle: TextStyle( color: Colors.red, ), constraints: BoxConstraints.expand(width: 300) ); // Caixa de diálogo de alerta usando o estilo de alerta personalizado Alert( context: context, style: alertStyle, type: AlertType.info, title: "RFLUTTER ALERT", desc: "Flutter é mais impressionante com o RFlutter Alert.", buttons: [ DialogButton( child: Text( "LINDO", style: TextStyle(color: Colors.white, fontSize: 20), ), onPressed: () => Navigator.pop(context), color: Color.fromRGBO(0, 179, 134, 1.0), radius: BorderRadius.circular(0.0), ), ], ).show(); } TÉCNICO EM INFORMÁTICA 5.2.8. Alert personalizado com imagem onAlertWithCustomImagePressed(context) { Alert( context: context, title: "RFLUTTER ALERT", desc: "Flutter é mais impressionante com o RFlutter Alert.", image: Image.asset("assets/success.png"), ).show(); } 5.2.9. Alert com conteúdo personalizado onAlertWithCustomContentPressed(context) { Alert( context: context, title: "LOGIN", content: Column( children: <Widget>[ TextField( decoration: InputDecoration( icon: Icon(Icons.account_circle), labelText: 'Username', ), ), TextField( obscureText: true, decoration: InputDecoration( icon: Icon(Icons.lock), labelText: 'Password', ), ), ], ), buttons: [ DialogButton( onPressed: () => Navigator.pop(context), child: Text( "LOGIN", style: TextStyle(color: Colors.white, fontSize: 20), ), ) ]).show(); } TÉCNICO EM INFORMÁTICA 6. Push notification Push notification é uma notificação que o usuário recebe em um aplicativo de smartphone, tablet ou em um navegador sem requisitá-la. Ao analisar o seu significado, fica mais fácil compreender. Enquanto notification é, obviamente, "notificação" em inglês, push é um falso cognato, pois soa parecido com "puxar", mas na realidade significa "empurrar". A tradução sugere, então, que a push notification é uma notificação que é empurrada ao usuário. Mas na prática não é bem assim. Isso porque ela só é enviada se o usuário, em algum momento, demonstrar interesse no conteúdo veiculado pela marca. No caso dos tablets e smartphones, esse interesse é o download do aplicativo que envia as push notifications. E no navegador? É quando o usuário acessa um site que abre uma espécie de popup com uma pergunta como "Você deseja receber notificações?". Então, as push notifications só vão aparecer para quem permitir. Além disso, quem fica incomodado pode, geralmente, ficar com o aplicativo e desativar as notificações nas configurações do app. No navegador, isso também pode ser feito na seção de configurações. Por tudo isso, a push notification é muito menos invasiva que o SMS (Short Message Service), por exemplo. Também conhecido como torpedo, o SMS é a velha mensagem de texto enviada para o celular. Muitas empresas ainda utilizam essa forma de se comunicar com os clientes, às vezes, sem que eles tenham manifestado o interesse em receber as informações enviadas. 6.1. Como o push notification funciona? Todo smartphone e tablet tem uma seção que lista as notificações recebidas. Isso porque os desenvolvedores dos principais sistemas operacionais (Apple, Google, Windows e Blackberry) possuem um serviço OSPNS, que permite o envio das mensagens. TÉCNICO EM INFORMÁTICA Nos smartphones com sistema Android, por exemplo, elas aparecem na tela bloqueada ou, quando desbloqueada, ao puxar o menu de opções da barra na parte de cima da tela. São essas as notificações que chamamos de push notifications. Quando chega uma nova, surge um popup na tela, que pode vir acompanhado de um som e de uma rápida vibração para chamar a atenção do usuário. Quando o usuário toca na push notification, ele é levado ao aplicativo que a enviou. Para uma marca se comunicar dessa maneira com um usuário, além de desenvolver um aplicativo, precisa de um servidor e de um software de envio de push notification, caso a empresa não possua tecnologia própria para isso. No caso das notificações que aparecem no navegador, a mensagem surge em um dos cantos da tela, com a opção de fechá-la (clicando no X) ou de clicar na mensagem e acessar o site do conteúdo que despertou o interesse. 6.2. Quais são as possibilidades de uso? Os conteúdos das mensagens enviadas via push notification podem ser dos mais variados. Vai depender muito do que a empresa faz ou do que aplicativo oferece, além da criatividade do desenvolvedor, é claro. O mais evidente é para informar sobre promoções em lojas virtuais. Por exemplo, você tem um aplicativo com e-commerce que vende sapatos e faz um dia promocional com frete grátis para compras acima de R$ 150. A melhor maneira de comunicar essa novidade aos clientes é enviando um push notification. A chegada de novos produtos e coleções também é um bom motivo para enviar notificações. E também há mensagens personalizadas, com base na própria atividade do usuário. Por exemplo, se ele fez uma compra via aplicativo, ele pode receber uma push notification informando que o produto foi enviado. Em aplicativos que fazem a mediação entre duas pontas na compra de produtos ou serviços, as notificações servem para avisar ao vendedor quando há uma venda ou interesse de um possível comprador, e ao comprador quando o vendedor respondeu sua dúvida. Se você anuncia um imóvel para alugar no Airbnb, por exemplo, o aplicativo do serviço lhe envia um push notification quando um usuário realiza uma reserva. Enfim, poderíamos listar infinitas outras possibilidades. Mas é mais prático recomendar que você identifique o público-alvo e pense nas mensagens de acordo com o seu interesse.Que tipo de novidade o usuário que baixou seu aplicativo gostaria de ver? TÉCNICO EM INFORMÁTICA 6.3. Quais são as possibilidades de uso? Neste exemplo será apresentada uma forma mais descomplicada ainda de enviar push notifications. Uma das tecnologias mais usada para envio de push é o firebase, devido a sua alta integração com o Flutter. Para gerenciar os envios dos push utilizaremos a plataforma OneSignal (https://onesignal.com) que é apresentada na figura ?? Figura ?? Página inicial do https://onesignal.com O OneSignal é uma plataforma que se comunica com o firebase para fazer o push, nele é possível ainda utilizar o crashlytics. Neste exemplo faremos a comunicação do OneSignal com um App desenvolvido em Flutter. 6.4. Criando uma conta no OneSignal Acesse o site https://onesignal.com e clique em Sign Up para acessar a tela inicial de cadastro apresentada na Figura?? Figura ?? Tela inicial de cadastro do site https://onesignal.com TÉCNICO EM INFORMÁTICA É possível fazer o cadastro no site utilizando um email pessoal ou utilizando contas do GitHub, Google ou Facebook. Após o processo de cadastro será envidadoum email de validação para a conta de email informada, conforme mostrado na Figura ?? Figura ?? Email de confirmação de cadastro enviado pelo OneSignal TÉCNICO EM INFORMÁTICA 6.5. Criando uma conta no Firebase O Firebase é um Baas (Backend as a Service) para aplicações Web e Mobile do Google, foi lançado em 2004 e com o passar dos anos cresceu muito, se tornando uma ferramenta que hoje para alguns projetos é a melhor opção, devido a quantidade de serviços oferecidos por ele, além da facilidade de implementação. BaaS ou BackEnd As A Service (MBaaS = Mobile BackEnd As A Service) é um serviço disponibilizado em que toda a estrutura do backend como: configuração de servidor, integração com banco de dados, sistema de push notification e outros serviços, que fazem parte do backend, estão completamente prontos para se integrar com o seu aplicativo. Após criar a conta no OneSignal precisamos criar um conta no Firebase ou usar a sua existente. Como o Firebase é uma ferramenta Google, por padrão todo usuário tem acesso a recursos básicos da ferramenta. Acessando https://firebase.google.com terá acesso a página inicial do firebase conforme apresentado na Figura ?? Figura ?? Página inicial do https://firebase.google.com 6.6. Integrando o Firebase com o OneSignal Agora com as duas contas criadas, vamos criar um app no Firebase e outro no OneSignal. Acesse o console do Firebase clicando no botão ir para console da página inicial na página apresentada na Figura ?? clique no botão Criar projeto TÉCNICO EM INFORMÁTICA Figura ?? Página inicial para criação de projeto Na próxima página informe o nome do projeto e selecione a opção de aceitação dos termos de uso do Firebase conforme apresentado na Figura ?? Figura ?? Passos iniciais para criação de projeto Na próxima página apresentada na Figura ?? é possível ativar as ferramentas Analytics do Google para o projeto TÉCNICO EM INFORMÁTICA Figura ?? Página de habilitação do Google Analytics para o projeto Na próxima página apresentada na Figura ?? é informada a localização do Analytics, efetuada a configuração padrão e a aceitação dos termos de uso e confidencialidade dos dados levantados pela Google. Figura ?? Página configuração de localização dos dados e termo de confidencialidade TÉCNICO EM INFORMÁTICA Projeto criado, vamos acessar a parte de configurações e navegar para Cloud Messaging. Para isso no item Visão Geral do Projeto, clique no ícone da engrenagem e depois em configurações do projeto conforme apresentado na Figura?? Figura ?? Acesso as configurações do projeto Na Na configuração do projeto acessaremos a aba Cloud Messaging para obter a Chave do servidor e o código do remetente necessários para a criação do app no OneSignal. A Figura ?? apresenta a aba Cloud Messaging que contém a Chave do servidor e o código do remetente que copiaremos para o projeto do app no OneSignal Figura ?? Aba Cloud Messaging das configurações do projeto no Firebase TÉCNICO EM INFORMÁTICA 6.7. Criando um App no OneSignal Após criarmos no Firebase, vamos criar o App no OneSignal. Para isso faça login no site do OneSignal conforme apresentado na Figura ?? Figura ?? Página de login no OneSignal Ao logar no OneSignal, se não possuir nenhum App, será apresentada a tela inicial para criação de um website ou app. Coloque um nome de sua preferência, lembrando que não se pode usar caracteres especiais e espaço em branco no nome. Selecione em seguida a plataforma Android e clique no botão Next: Configure Your Plataform conforme mostrado na Figura??. Figura ?? Tela inicial de criação de app no OneSignal TÉCNICO EM INFORMÁTICA A tela apresentada na Figura ?? solicita a chave do servidor e o Código do usuário do projeto criado anteriormente no Firebase. Estes dados conforme mencionado anteriormente se encontram em configurações de projeto / Cloud Messaging Figura ?? Tela Configure Platform do OneSignal e Cloud Messaging do Firebase Pressione next e na próxima tela mostrada na Figura ?? escolha Native Android. Figura ?? Página de seleção da Plataforma TÉCNICO EM INFORMÁTICA Ao pressionar o botão next será exibida a tela apresentada na Figura ??. Guarde o Your App ID que será utilizado como parâmetro na programação Flutter. Figura ?? Página de finalização de configuração do App. Your App ID será a key usada no seu app flutter para identificar seu aplicativo. Então deixe isso aberto no navegador pois iremos utilizar. Concluímos as configurações básicas, agora iremos colocar a mão na massa, com o aplicativo. Daqui em diante fica a sua escolha, de criar um app novo ou usar em um projeto existente. Abra o vs code e crie um projeto flutter com o nome onesignal_notification. Para isso pressione as teclas Ctrl+Shift+P, escolha flutter project conforme apresentado na Figura ?? Figura ?? Tela inicial de criação de Projeto Flutter no VS Code. TÉCNICO EM INFORMÁTICA Após clicar em Flutter Projetc será exibida a tela apresentada na Figura ??. Informe o nome do projeto, no nosso caso onesignal_notification. Lembre-se nomes de projetos em Flutter não podem possuir letras maiúsculas, espaços em branco e caracteres especiais. Figura ?? Tela de criação de projeto Flutter no VS Code Após criar o projeto será exibida uma tela conforme apresentado na Figura?? que solicita a indicação da localização de armazenamento de todos os recursos e códigos Figura ?? Janela para seleção de local para criação de pasta de projeto TÉCNICO EM INFORMÁTICA Agora com nosso projeto criado no vs code, conforme apresentado na Figura ??, iremos abrir o arquivo pubspec.yam que é rum arquivo de metadados responsável por gerenciar as dependências do projeto como bibliotecas e pacotes. Os pacotes existentes permitem muitos casos de uso, por exemplo, solicitações de rede http , navegação personalizada / tratamento de rotas, integração com APIs de dispositivos (url_launcher e battery) e uso de SDKs de plataformas de terceiros como Firebase (FlutterFire). Figura ?? Estrutura do arquivo principal do projeto criado. TÉCNICO EM INFORMÁTICA No arquivo pubspec.yam apresentado na Figura ?? acrescentaremos o pacote onesignal_flutter para que a aplicação possa utilizar os recursos do OneSignal. Abaixo temos parte do código Agora precisamos configurar os arquivos do android. Primeiro abra o arquivo build.gradle apresentado na Figura ??, localizado em: android/build.gradle Figura ?? Arquivo build.gradle TÉCNICO EM INFORMÁTICA Vamos adicionar a seguinte linha: Em repositories repositories { // ... // Gradle Plugin Portal maven { url 'https://plugins.gradle.org/m2/' } } Já em dependencies dependencies { // ... // OneSignal-Gradle-Plugin classpath 'gradle.plugin.com.onesignal:onesignal-gradle-plugin:[0.12.1, 0.99.99]' } O resultado da modificação é apresentado na Figura ?? Figura ?? Arquivo build.gradle modificado TÉCNICO EM INFORMÁTICA Agora vamos em outro arquivo build.gradle, localizado em: android/app/build.gradle e no final dele iremos colar a seguinte linha: apply plugin: 'com.onesignal.androidsdk.onesignal-gradle-plugin A Figura ?? apresenta o build.gradle, localizado em: android/app/build.gradle já modificado Figura ?? Arquivo build.gradle modificado Pronto! Temos tudo configurado para receber o código no flutter para inicializar o OneSignal. Agora vamos para o código no Flutter. Iremos criar a estrutura de pastas e arquivos conforme apresentado na Figura ??: Figura ?? Estrutura de arquivos TÉCNICO EM INFORMÁTICA Nossa arquivo main.dart ficou da seguinte forma: import 'package:flutter/material.dart'; import 'Pages/home/bloc/home_page.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter One Signal', theme: ThemeData( primarySwatch: Colors.blue, ), home: HomePage(), ); } } e nossa pages/home/home_page.dart import 'package:flutter/material.dart'; class
Compartilhar