Flutter - Guía rápida

En general, desarrollar una aplicación móvil es una tarea compleja y desafiante. Hay muchos marcos disponibles para desarrollar una aplicación móvil. Android proporciona un marco nativo basado en el lenguaje Java e iOS proporciona un marco nativo basado en el lenguaje Objective-C / Swift.

Sin embargo, para desarrollar una aplicación que admita ambos sistemas operativos, necesitamos codificar en dos lenguajes diferentes usando dos marcos diferentes. Para ayudar a superar esta complejidad, existen marcos móviles compatibles con ambos sistemas operativos. Estos marcos van desde un marco de aplicación móvil híbrido basado en HTML simple (que usa HTML para la interfaz de usuario y JavaScript para la lógica de la aplicación) hasta un marco específico de lenguaje complejo (que hace el trabajo pesado de convertir código en código nativo). Independientemente de su simplicidad o complejidad, estos marcos siempre tienen muchas desventajas, uno de los principales inconvenientes es su lento rendimiento.

En este escenario, Flutter, un marco simple y de alto rendimiento basado en el lenguaje Dart, proporciona un alto rendimiento al representar la interfaz de usuario directamente en el lienzo del sistema operativo en lugar de a través del marco nativo.

Flutter también ofrece muchos widgets (UI) listos para usar para crear una aplicación moderna. Estos widgets están optimizados para entornos móviles y diseñar la aplicación utilizando widgets es tan simple como diseñar HTML.

Para ser específico, la aplicación Flutter es en sí misma un widget. Los widgets de Flutter también admiten animaciones y gestos. La lógica de la aplicación se basa en la programación reactiva. El widget puede tener opcionalmente un estado. Al cambiar el estado del widget, Flutter automáticamente (programación reactiva) comparará el estado del widget (antiguo y nuevo) y renderizará el widget con solo los cambios necesarios en lugar de volver a renderizar todo el widget.

Discutiremos la arquitectura completa en los próximos capítulos.

Características de Flutter

Flutter framework ofrece las siguientes características a los desarrolladores:

  • Marco moderno y reactivo.

  • Utiliza el lenguaje de programación Dart y es muy fácil de aprender.

  • Desarrollo rápido.

  • Interfaces de usuario hermosas y fluidas.

  • Gran catálogo de widgets.

  • Ejecuta la misma interfaz de usuario para múltiples plataformas.

  • Aplicación de alto rendimiento.

Ventajas de Flutter

Flutter viene con widgets hermosos y personalizables para un alto rendimiento y una aplicación móvil excepcional. Cumple con todas las necesidades y requisitos personalizados. Además de estos, Flutter ofrece muchas más ventajas como se menciona a continuación:

  • Dart tiene un gran repositorio de paquetes de software que le permite ampliar las capacidades de su aplicación.

  • Los desarrolladores necesitan escribir una única base de código para ambas aplicaciones (plataformas Android e iOS). Flutter también puede extenderse a otras plataformas en el futuro.

  • Flutter necesita menos pruebas. Debido a su base de código único, es suficiente si escribimos pruebas automatizadas una vez para ambas plataformas.

  • La simplicidad de Flutter lo convierte en un buen candidato para un desarrollo rápido. Su capacidad de personalización y extensibilidad lo hace aún más poderoso.

  • Con Flutter, los desarrolladores tienen control total sobre los widgets y su diseño.

  • Flutter ofrece excelentes herramientas de desarrollo, con una increíble recarga en caliente.

Desventajas de Flutter

A pesar de sus muchas ventajas, flutter tiene los siguientes inconvenientes:

  • Dado que está codificado en lenguaje Dart, un desarrollador necesita aprender un nuevo idioma (aunque es fácil de aprender).

  • El marco moderno intenta separar la lógica y la interfaz de usuario tanto como sea posible, pero en Flutter, la interfaz de usuario y la lógica están entremezcladas. Podemos superar esto usando codificación inteligente y usando un módulo de alto nivel para separar la interfaz de usuario y la lógica.

  • Flutter es otro marco para crear aplicaciones móviles. Los desarrolladores están teniendo dificultades para elegir las herramientas de desarrollo adecuadas en un segmento enormemente poblado.

Este capítulo lo guiará a través de la instalación de Flutter en su computadora local en detalle.

Instalación en Windows

En esta sección, veamos cómo instalar Flutter SDK y sus requisitos en un sistema Windows.

Step 1 - Ir a la URL,https://flutter.dev/docs/get-started/install/windowsy descargue la última versión de Flutter SDK. En abril de 2019, la versión es 1.2.1 y el archivo es flutter_windows_v1.2.1-stable.zip.

Step 2 - Descomprima el archivo zip en una carpeta, diga C: \ flutter \

Step 3 - Actualice la ruta del sistema para incluir el directorio bin de flutter.

Step 4 - Flutter proporciona una herramienta, flutter doctor para comprobar que se cumplen todos los requisitos del desarrollo del flutter.

flutter doctor

Step 5 - Ejecutar el comando anterior analizará el sistema y mostrará su informe como se muestra a continuación -

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, v1.2.1, on Microsoft Windows [Version
10.0.17134.706], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version
28.0.3)
[√] Android Studio (version 3.2)
[√] VS Code, 64-bit edition (version 1.29.1)
[!] Connected device
! No devices available
! Doctor found issues in 1 category.

El informe dice que todas las herramientas de desarrollo están disponibles pero el dispositivo no está conectado. Podemos solucionar esto conectando un dispositivo Android a través de USB o iniciando un emulador de Android.

Step 6 - Instale el último SDK de Android, si lo informa Flutter Doctor

Step 7 - Instale la última versión de Android Studio, si lo informa flutter doctor

Step 8 - Inicie un emulador de Android o conecte un dispositivo Android real al sistema.

Step 9- Instale el complemento Flutter y Dart para Android Studio. Proporciona una plantilla de inicio para crear una nueva aplicación Flutter, una opción para ejecutar y depurar la aplicación Flutter en el propio estudio de Android, etc.

  • Abra Android Studio.

  • Haga clic en Archivo → Configuración → Complementos.

  • Selecciona el complemento Flutter y haz clic en Instalar.

  • Haga clic en Sí cuando se le solicite instalar el complemento Dart.

  • Reinicia el estudio de Android.

Instalación en MacOS

Para instalar Flutter en MacOS, deberá seguir los siguientes pasos:

Step 1 - Ir a la URL,https://flutter.dev/docs/get-started/install/macosy descargue el último SDK de Flutter. En abril de 2019, la versión es 1.2.1 y el archivo es flutter_macos_v1.2.1- stable.zip.

Step 2 - Descomprima el archivo zip en una carpeta, diga / ruta / a / flutter

Step 3 - Actualice la ruta del sistema para incluir el directorio bin de flutter (en el archivo ~ / .bashrc).

> export PATH = "$PATH:/path/to/flutter/bin"

Step 4 - Habilite la ruta actualizada en la sesión actual usando el siguiente comando y luego verifíquelo también.

source ~/.bashrc
source $HOME/.bash_profile
echo $PATH

Flutter proporciona una herramienta, un doctor de flutter para comprobar que se cumplen todos los requisitos del desarrollo del flutter. Es similar a la contraparte de Windows.

Step 5 - Instale el último XCode, si lo informa Flutter Doctor

Step 6 - Instale el último SDK de Android, si lo informa flutter doctor

Step 7 - Instale el último Android Studio, si lo informa Flutter Doctor

Step 8 - Inicie un emulador de Android o conecte un dispositivo Android real al sistema para desarrollar una aplicación de Android.

Step 9 - Abra el simulador de iOS o conecte un dispositivo iPhone real al sistema para desarrollar la aplicación iOS.

Step 10- Instale el complemento Flutter y Dart para Android Studio. Proporciona la plantilla de inicio para crear una nueva aplicación Flutter, opción para ejecutar y depurar la aplicación Flutter en el propio estudio de Android, etc.

  • Abrir Android Studio

  • Hacer clic Preferences → Plugins

  • Seleccione el complemento Flutter y haga clic en Instalar

  • Haga clic en Sí cuando se le solicite instalar el complemento Dart.

  • Reinicia el estudio de Android.

En este capítulo, creemos una aplicación Flutter simple para comprender los conceptos básicos de la creación de una aplicación Flutter en Android Studio.

Step 1 - Abrir Android Studio

Step 2- Crear proyecto Flutter. Para esto, haga clic enFile → New → New Flutter Project

Step 3- Seleccione Aplicación Flutter. Para esto, seleccioneFlutter Application y haga clic en Next.

Step 4 - Configure la aplicación como se muestra a continuación y haga clic en Next.

  • Nombre del proyecto: hello_app

  • Ruta del SDK de Flutter: <path_to_flutter_sdk>

  • Localización del proyecto: <path_to_project_folder>

  • Descripción: Flutter based hello world application

Step 5 - Configurar proyecto.

Establecer el dominio de la empresa como flutterapp.tutorialspoint.com y haga clic en Finish.

Step 6 - Introduzca el dominio de la empresa.

Android Studio crea una aplicación de aleteo completamente funcional con una funcionalidad mínima. Comprobemos la estructura de la aplicación y luego cambiemos el código para hacer nuestra tarea.

La estructura de la aplicación y su propósito es la siguiente:

Aquí se explican varios componentes de la estructura de la aplicación:

  • android - Código fuente generado automáticamente para crear aplicaciones de Android

  • ios - Código fuente generado automáticamente para crear una aplicación ios

  • lib - Carpeta principal que contiene el código de Dart escrito en el marco de flutter

  • ib/main.dart - Punto de entrada de la aplicación Flutter

  • test - Carpeta que contiene el código Dart para probar la aplicación Flutter

  • test/widget_test.dart - Código de muestra

  • .gitignore - Archivo de control de versiones de Git

  • .metadata - generado automáticamente por las herramientas de aleteo

  • .packages - generado automáticamente para rastrear los paquetes de flutter

  • .iml - archivo de proyecto utilizado por Android Studio

  • pubspec.yaml - Usado por Pub, Administrador de paquetes Flutter

  • pubspec.lock - Generado automáticamente por el administrador de paquetes Flutter, Pub

  • README.md - Archivo de descripción del proyecto escrito en formato Markdown

Step 7- Reemplace el código de dardos en el archivo lib / main.dart con el siguiente código -

import 'package:flutter/material.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: 'Hello World Demo Application',
         theme: ThemeData(
            primarySwatch: Colors.blue,
         ),
         home: MyHomePage(title: 'Home page'),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;

   @override
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title),
         ),
         body: Center(
            child:
            Text(
               'Hello World',
            )
         ),
      );
   }
}

Entendamos el código de dardos línea por línea.

  • Line 1- importa el paquete flutter, material . El material es un paquete de aleteo para crear una interfaz de usuario de acuerdo con las pautas de diseño de materiales especificadas por Android.

  • Line 3- Este es el punto de entrada de la aplicación Flutter. Llama a la función runApp y le pasa un objeto de la clase MyApp . El propósito de la función runApp es adjuntar el widget dado a la pantalla.

  • Line 5-17- El widget se utiliza para crear una interfaz de usuario en el marco de flutter. StatelessWidget es un widget, que no mantiene ningún estado del widget. MyApp extiende StatelessWidget y anula su método de compilación . El propósito del método de compilación es crear una parte de la interfaz de usuario de la aplicación. Aquí, el método de compilación usa MaterialApp , un widget para crear la interfaz de usuario de nivel raíz de la aplicación. Tiene tres propiedades: título, tema y hogar .

    • title es el título de la aplicación

    • tema es el tema del widget. Aquí, configuramos el azul como el color general de la aplicación usando la clase ThemeData y su propiedad, primarySwatch .

    • home es la interfaz de usuario interna de la aplicación, que configuramos otro widget, MyHomePage

  • Line 19 - 38- MyHomePage es igual que MyApp, excepto que devuelve Scaffold Widget. Scaffold es un widget de nivel superior junto al widget MaterialApp que se utiliza para crear un diseño de material conforme a la interfaz de usuario. Tiene dos propiedades importantes, appBar para mostrar el encabezado de la aplicación y el cuerpo para mostrar el contenido real de la aplicación. AppBar es otro widget para representar el encabezado de la aplicación y lo hemos usado en la propiedad appBar . En la propiedad del cuerpo , hemos utilizado el widget Center , que lo centra en el widget hijo. El texto es el widget final y más interno para mostrar el texto y se muestra en el centro de la pantalla.

Step 8 - Ahora, ejecute la aplicación usando, Run → Run main.dart

Step 9 - Finalmente, el resultado de la aplicación es el siguiente -

En este capítulo, analicemos la arquitectura del marco Flutter.

Widgets

El concepto central del marco Flutter es In Flutter, Everything is a widget. Los widgets son básicamente componentes de la interfaz de usuario que se utilizan para crear la interfaz de usuario de la aplicación.

En Flutter , la aplicación es en sí misma un widget. La aplicación es el widget de nivel superior y su interfaz de usuario se construye usando uno o más elementos secundarios (widgets), que nuevamente se construyen usando sus widgets secundarios. Estacomposability La función nos ayuda a crear una interfaz de usuario de cualquier complejidad.

Por ejemplo, la jerarquía de widgets de la aplicación Hello World (creada en el capítulo anterior) es como se especifica en el siguiente diagrama:

Aquí los siguientes puntos son dignos de mención:

  • MyApp es el widget creado por el usuario y se crea utilizando el widget nativo de Flutter, MaterialApp .

  • MaterialApp tiene una propiedad de inicio para especificar la interfaz de usuario de la página de inicio, que nuevamente es un widget creado por el usuario, MyHomePage .

  • MyHomePage se construye usando otro widget nativo de flutter, Scaffold

  • Scaffold tiene dos propiedades: body y appBar

  • body se usa para especificar su interfaz de usuario principal y appBar se usa para especificar su interfaz de usuario de encabezado

  • La interfaz de usuario del encabezado se construye usando el widget nativo de flutter, AppBar y la interfaz de usuario del cuerpo se construye usando el widget Center .

  • El widget Center tiene una propiedad, Child , que se refiere al contenido real y se construye usando el widget Text

Gestos

Los widgets de Flutter admiten la interacción a través de un widget especial, GestureDetector . GestureDetector es un widget invisible que tiene la capacidad de capturar las interacciones del usuario, como tocar, arrastrar, etc., de su widget secundario. Muchos widgets nativos de Flutter admiten la interacción mediante el uso de GestureDetector . También podemos incorporar una función interactiva en el widget existente componiéndolo con el widget GestureDetector . Aprenderemos los gestos por separado en los próximos capítulos.

Concepto de Estado

Los widgets de Flutter admiten el mantenimiento del estado al proporcionar un widget especial, StatefulWidget . El widget debe derivarse del widget StatefulWidget para admitir el mantenimiento del estado y todos los demás widgets deben derivarse de StatefulWidget . Los widgets Flutter sonreactiveen nativo. Esto es similar a reactjs y StatefulWidget se auto re- vuelve cada vez que se cambia su estado interno. La reproducción se optimiza al encontrar la diferencia entre la interfaz de usuario del widget anterior y la nueva y al procesar solo los cambios necesarios

Capas

El concepto más importante del marco Flutter es que el marco está agrupado en varias categorías en términos de complejidad y claramente organizado en capas de complejidad decreciente. Una capa se construye utilizando su capa de siguiente nivel inmediata. La capa más superior es un widget específico para Android e iOS . La siguiente capa tiene todos los widgets nativos de flutter. La siguiente capa es la capa de renderizado , que es un componente de renderizado de bajo nivel y renderiza todo en la aplicación Flutter. Las capas se reducen al código específico de la plataforma central

La descripción general de una capa en Flutter se especifica en el siguiente diagrama:

Los siguientes puntos resumen la arquitectura de Flutter:

  • En Flutter, todo es un widget y un widget complejo se compone de widgets ya existentes.

  • Las funciones interactivas se pueden incorporar siempre que sea necesario mediante el widget GestureDetector .

  • El estado de un widget se puede mantener siempre que sea necesario utilizando el widget StatefulWidget .

  • Flutter ofrece un diseño en capas para que se pueda programar cualquier capa según la complejidad de la tarea.

Discutiremos todos estos conceptos en detalle en los próximos capítulos.

Dart es un lenguaje de programación de uso general de código abierto. Fue desarrollado originalmente por Google. Dart es un lenguaje orientado a objetos con sintaxis de estilo C. Admite conceptos de programación como interfaces, clases, a diferencia de otros lenguajes de programación, Dart no admite matrices. Las colecciones de Dart se pueden utilizar para replicar estructuras de datos como matrices, genéricos y tipificación opcional.

El siguiente código muestra un programa Dart simple:

void main() {
   print("Dart language is easy to learn");
}

Variables y tipos de datos

La variable se denomina ubicación de almacenamiento y los tipos de datos simplemente se refieren al tipo y tamaño de los datos asociados con las variables y funciones.

Dart usa la palabra clave var para declarar la variable. La sintaxis de var se define a continuación,

var name = 'Dart';

Las palabras clave final y const se utilizan para declarar constantes. Se definen a continuación:

void main() {
   final a = 12;
   const pi = 3.14;
   print(a);
   print(pi);
}

El lenguaje Dart admite los siguientes tipos de datos:

  • Numbers - Se utiliza para representar literales numéricos - Integer y Double.

  • Strings- Representa una secuencia de caracteres. Los valores de cadena se especifican entre comillas simples o dobles.

  • Booleans- Dart usa la palabra clave bool para representar valores booleanos: verdadero y falso.

  • Lists and Maps- Se utiliza para representar una colección de objetos. Una lista simple se puede definir de la siguiente manera:

void main() {
   var list = [1,2,3,4,5];
   print(list);
}

La lista que se muestra arriba produce la lista [1,2,3,4,5].

El mapa se puede definir como se muestra aquí:

void main() {
   var mapping = {'id': 1,'name':'Dart'};
   print(mapping);
}
  • Dynamic- Si el tipo de variable no está definido, entonces su tipo predeterminado es dinámico. El siguiente ejemplo ilustra la variable de tipo dinámico:

void main() {
   dynamic name = "Dart";
   print(name);
}

Toma de decisiones y bucles

Un bloque de toma de decisiones evalúa una condición antes de que se ejecuten las instrucciones. Dart admite declaraciones If, If..else y switch.

Los bucles se utilizan para repetir un bloque de código hasta que se cumple una condición específica. Dart admite bucles for, for..in, while y do.. while.

Entendamos un ejemplo simple sobre el uso de declaraciones de control y bucles:

void main() {
   for( var i = 1 ; i <= 10; i++ ) {
      if(i%2==0) {
         print(i);
      }
   }
}

El código anterior imprime los números pares del 1 al 10.

Funciones

Una función es un grupo de declaraciones que juntas realizan una tarea específica. Veamos una función simple en Dart como se muestra aquí:

void main() {
   add(3,4);
}
void add(int a,int b) {
   int c;
   c = a+b;
   print(c);
}

La función anterior suma dos valores y produce 7 como salida.

Programación orientada a objetos

Dart es un lenguaje orientado a objetos. Admite funciones de programación orientadas a objetos como clases, interfaces, etc.

Una clase es un plan para crear objetos. Una definición de clase incluye lo siguiente:

  • Fields
  • Getters y setters
  • Constructors
  • Functions

Ahora, creemos una clase simple usando las definiciones anteriores:

class Employee {
   String name;
   
   //getter method
   String get emp_name {
      return name;
   }
   //setter method
   void set emp_name(String name) {
      this.name = name;
   }
   //function definition
   void result() {
      print(name);
   }
}
void main() {
   //object creation
   Employee emp = new Employee();
   emp.name = "employee1";
   emp.result(); //function call
}

Como aprendimos en el capítulo anterior, los widgets lo son todo en el marco de Flutter. Ya hemos aprendido a crear nuevos widgets en capítulos anteriores.

En este capítulo, entendamos el concepto real detrás de la creación de los widgets y los diferentes tipos de widgets disponibles en el marco de Flutter .

Vamos a ver el Hello World de aplicación MyHomePage de widgets. El código para este propósito es el que se indica a continuación:

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar(title: Text(this.title), ), 
         body: Center(child: Text( 'Hello World',)),
      );
   }
}

Aquí, hemos creado un nuevo widget ampliando StatelessWidget .

Tenga en cuenta que StatelessWidget solo requiere que se implemente una única compilación de método en su clase derivada. El método de construcción obtiene el entorno de contexto necesario para construir los widgets a través del parámetro BuildContext y devuelve el widget que crea.

En el código, hemos usado title como uno de los argumentos del constructor y también usamos Key como otro argumento. El título se usa para mostrar el título y la clave se usa para identificar el widget en el entorno de construcción.

Aquí, el método de construcción llama al método de construcción de Scaffold , que a su vez llama al método de construcción de AppBar y Center para construir su interfaz de usuario.

Finalmente, el método de construcción Center llama al método de construcción Text .

Para una mejor comprensión, la representación visual del mismo se da a continuación:

Visualización de compilación de widgets

En Flutter , los widgets se pueden agrupar en varias categorías según sus características, como se enumeran a continuación:

  • Widgets específicos de la plataforma
  • Diseño de widgets
  • Widgets de mantenimiento de estado
  • Widgets básicos / independientes de la plataforma

Analicemos cada uno de ellos en detalle ahora.

Widgets específicos de la plataforma

Flutter tiene widgets específicos para una plataforma en particular: Android o iOS.

Los widgets específicos de Android están diseñados de acuerdo con las pautas de diseño de materiales del sistema operativo Android. Los widgets específicos de Android se denominan widgets de material .

Los widgets específicos de iOS están diseñados de acuerdo con las pautas de interfaz humana de Apple y se denominan widgets de Cupertino .

Algunos de los widgets de material más utilizados son los siguientes:

  • Scaffold
  • AppBar
  • BottomNavigationBar
  • TabBar
  • TabBarView
  • ListTile
  • RaisedButton
  • FloatingActionButton
  • FlatButton
  • IconButton
  • DropdownButton
  • PopupMenuButton
  • ButtonBar
  • TextField
  • Checkbox
  • Radio
  • Switch
  • Slider
  • Selectores de fecha y hora
  • SimpleDialog
  • AlertDialog

Algunos de los widgets de Cupertino más utilizados son los siguientes:

  • CupertinoButton
  • CupertinoPicker
  • CupertinoDatePicker
  • CupertinoTimerPicker
  • CupertinoNavigationBar
  • CupertinoTabBar
  • CupertinoTabScaffold
  • CupertinoTabView
  • CupertinoTextField
  • CupertinoDialog
  • CupertinoDialogAction
  • CupertinoFullscreenDialogTransition
  • CupertinoPageScaffold
  • CupertinoPageTransition
  • CupertinoActionSheet
  • CupertinoActivityIndicator
  • CupertinoAlertDialog
  • CupertinoPopupSurface
  • CupertinoSlider

Diseño de widgets

En Flutter, se puede crear un widget componiendo uno o más widgets. Para componer varios widgets en un solo widget, Flutter proporciona una gran cantidad de widgets con función de diseño. Por ejemplo, el widget secundario se puede centrar mediante el widget Center .

Algunos de los widgets de diseño más populares son los siguientes:

  • Container- Una caja rectangular decorada con widgets BoxDecoration con fondo, borde y sombra.

  • Center - Centra su widget hijo.

  • Row - Organizar a sus hijos en dirección horizontal.

  • Column - Organizar a sus hijos en dirección vertical.

  • Stack - Colocar uno encima del otro.

Comprobaremos los widgets de diseño en detalle en el próximo capítulo Introducción a los widgets de diseño .

Widgets de mantenimiento de estado

En Flutter, todos los widgets se derivan de StatelessWidget o StatefulWidget .

El widget derivado de StatelessWidget no tiene información de estado, pero puede contener un widget derivado de StatefulWidget . La naturaleza dinámica de la aplicación es a través del comportamiento interactivo de los widgets y el estado cambia durante la interacción. Por ejemplo, al tocar un botón de contador aumentará / disminuirá el estado interno del contador en uno y la naturaleza reactiva del widget Flutter volverá a renderizar automáticamente el widget usando nueva información de estado.

Aprenderemos el concepto de los widgets StatefulWidget en detalle en el próximo capítulo de administración de estados .

Widgets básicos / independientes de la plataforma

Flutter proporciona una gran cantidad de widgets básicos para crear una interfaz de usuario simple y compleja de manera independiente de la plataforma. Veamos algunos de los widgets básicos de este capítulo.

Text

El widget de texto se utiliza para mostrar un trozo de cuerda. El estilo de la cadena se puede establecer mediante la propiedad de estilo y la clase TextStyle . El código de muestra para este propósito es el siguiente:

Text('Hello World!', style: TextStyle(fontWeight: FontWeight.bold))

El widget de texto tiene un constructor especial, Text.rich , que acepta al hijo de tipo TextSpan para especificar la cadena con un estilo diferente. El widget TextSpan es de naturaleza recursiva y acepta TextSpan como sus hijos. El código de muestra para este propósito es el siguiente:

Text.rich( 
   TextSpan( 
      children: <TextSpan>[ 
         TextSpan(text: "Hello ", style:  
         TextStyle(fontStyle: FontStyle.italic)),  
         TextSpan(text: "World", style: 
         TextStyle(fontWeight: FontWeight.bold)),  
      ], 
   ), 
)

Las propiedades más importantes del widget de texto son las siguientes:

  • maxLines, int - Número máximo de líneas para mostrar

  • overflow, TextOverFlow- Especifique cómo se maneja el desbordamiento visual usando la clase TextOverFlow

  • style, TextStyle- Especifique el estilo de la cadena usando la clase TextStyle

  • textAlign, TextAlign- Alineación del texto como derecha, izquierda, justificar, etc., usando la clase TextAlign

  • textDirection, TextDirection - Dirección de flujo del texto, de izquierda a derecha o de derecha a izquierda

Image

El widget de imagen se utiliza para mostrar una imagen en la aplicación. El widget de imagen proporciona diferentes constructores para cargar imágenes de múltiples fuentes y son los siguientes:

  • Image- Cargador de imágenes genérico usando ImageProvider

  • Image.asset - Cargar imagen de los activos del proyecto flutter

  • Image.file - Cargar imagen de la carpeta del sistema

  • Image.memory - Cargar imagen de la memoria

  • Image.Network - Cargar imagen de la red

La opción más fácil para cargar y mostrar una imagen en Flutter es incluir la imagen como activos de la aplicación y cargarla en el widget a pedido.

  • Cree una carpeta, activos en la carpeta del proyecto y coloque las imágenes necesarias.

  • Especifique los activos en pubspec.yaml como se muestra a continuación:

flutter: 
   assets: 
      - assets/smiley.png
  • Ahora, cargue y muestre la imagen en la aplicación.

Image.asset('assets/smiley.png')
  • El código fuente completo del widget MyHomePage de la aplicación hello world y el resultado se muestra a continuación -.

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar( title: Text(this.title), ), 
         body: Center( child: Image.asset("assets/smiley.png")),
      ); 
   }
}

La imagen cargada es como se muestra a continuación:

Las propiedades más importantes del widget de imagen son las siguientes:

  • image, ImageProvider - Imagen real para cargar

  • width, double - Ancho de la imagen

  • height, double - Alto de la imagen

  • alignment, AlignmentGeometry - Cómo alinear la imagen dentro de sus límites

Icon

El widget de icono se utiliza para mostrar un glifo de una fuente descrita en la clase IconData . El código para cargar un icono de correo electrónico simple es el siguiente:

Icon(Icons.email)

El código fuente completo para aplicarlo en la aplicación hello world es el siguiente:

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center( child: Icon(Icons.email)),
      );
   }
}

El icono cargado es como se muestra a continuación:

Dado que el concepto central de Flutter es Todo es widget , Flutter incorpora una funcionalidad de diseño de interfaz de usuario en los propios widgets. Flutter proporciona una gran cantidad de widgets especialmente diseñados como Container, Center, Align , etc., solo con el propósito de diseñar la interfaz de usuario. Los widgets se crean componiendo otros widgets normalmente usan widgets de diseño. Aprendamos el concepto de diseño de Flutter en este capítulo.

Tipo de widgets de diseño

Los widgets de diseño se pueden agrupar en dos categorías distintas según su hijo:

  • Widget que apoya a un solo niño
  • Widget que admite varios niños

Aprendamos ambos tipos de widgets y su funcionalidad en las próximas secciones.

Widgets para un solo niño

En esta categoría, los widgets solo tendrán un widget como hijo y cada widget tendrá una funcionalidad de diseño especial.

Por ejemplo, el widget Center simplemente centra su widget secundario con respecto a su widget principal y el widget Container proporciona una flexibilidad completa para colocarlo en cualquier lugar dado dentro de él usando diferentes opciones como relleno, decoración, etc.

Los widgets de un solo niño son excelentes opciones para crear widgets de alta calidad con una sola funcionalidad como botón, etiqueta, etc.

El código para crear un botón simple usando el widget Container es el siguiente:

class MyButton extends StatelessWidget {
   MyButton({Key key}) : super(key: key); 

   @override 
   Widget build(BuildContext context) {
      return Container(
         decoration: const BoxDecoration(
            border: Border(
               top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
               bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
            ),
         ),
         child: Container(
            padding: const
            EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
            decoration: const BoxDecoration(
               border: Border(
                  top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
                  bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
               ),
               color: Colors.grey,
            ),
            child: const Text(
               'OK',textAlign: TextAlign.center, style: TextStyle(color: Colors.black)
            ), 
         ), 
      ); 
   }
}

Aquí, hemos utilizado dos widgets: un widget de contenedor y un widget de texto . El resultado del widget es un botón personalizado como se muestra a continuación:

Veamos algunos de los widgets de diseño de un solo niño más importantes proporcionados por Flutter :

  • Padding- Se usa para organizar su widget secundario por el relleno dado. Aquí, la clase EdgeInsets puede proporcionar el relleno .

  • Align- Alinee su widget hijo dentro de sí mismo usando el valor de la propiedad de alineación . El valor de la propiedad de alineación puede ser proporcionado por la clase FractionalOffset . La clase FractionalOffset especifica las compensaciones en términos de una distancia desde la parte superior izquierda.

Algunos de los posibles valores de compensaciones son los siguientes:

  • FractionalOffset (1.0, 0.0) representa la parte superior derecha.

  • FractionalOffset (0.0, 1.0) representa la parte inferior izquierda.

A continuación, se muestra un código de muestra sobre compensaciones:

Center(
   child: Container(
      height: 100.0, 
      width: 100.0, 
      color: Colors.yellow, child: Align(
         alignment: FractionalOffset(0.2, 0.6),
         child: Container( height: 40.0, width:
            40.0, color: Colors.red,
         ), 
      ), 
   ), 
)
  • FittedBox - Escala el widget secundario y luego lo coloca de acuerdo con el ajuste especificado.

  • AspectRatio - Intenta ajustar el tamaño del widget secundario a la relación de aspecto especificada

  • ConstrainedBox

  • Baseline

  • FractinallySizedBox

  • IntrinsicHeight

  • IntrinsicWidth

  • LiimitedBox

  • OffStage

  • OverflowBox

  • SizedBox

  • SizedOverflowBox

  • Transform

  • CustomSingleChildLayout

Nuestra aplicación Hello World utiliza widgets de diseño basados ​​en materiales para diseñar la página de inicio. Modifiquemos nuestra aplicación hello world para crear la página de inicio utilizando widgets de diseño básicos como se especifica a continuación:

  • Container - Widget contenedor genérico, de un solo hijo, basado en cuadro con alineación, relleno, borde y margen junto con características de estilo enriquecidas.

  • Center - Widget de contenedor secundario simple, único, que centra su widget secundario.

El código modificado del widget MyHomePage y MyApp es el siguiente:

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return MyHomePage(title: "Hello World demo app");
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override
   Widget build(BuildContext context) {
      return Container(
         decoration: BoxDecoration(color: Colors.white,),
         padding: EdgeInsets.all(25), child: Center(
            child:Text(
               'Hello World', style: TextStyle(
                  color: Colors.black, letterSpacing: 0.5, fontSize: 20,
               ),
               textDirection: TextDirection.ltr,
            ),
         )
      );
   }
}

Aquí,

  • El widget de contenedor es el widget de nivel superior o raíz. El contenedor se configura utilizando la propiedad de decoración y relleno para diseñar su contenido.

  • BoxDecoration tiene muchas propiedades como color, borde, etc., para decorar el widget Container y aquí, el color se usa para establecer el color del contenedor.

  • El relleno del widget Container se establece mediante la clase dgeInsets , que proporciona la opción de especificar el valor de relleno.

  • Center es el widget secundario del widget Container . Nuevamente, Text es el elemento secundario del widget Center . El texto se usa para mostrar el mensaje y el Centro se usa para centrar el mensaje de texto con respecto al widget principal, Container .

El resultado final del código proporcionado anteriormente es una muestra de diseño como se muestra a continuación:

Varios widgets secundarios

En esta categoría, un widget determinado tendrá más de un widget secundario y el diseño de cada widget es único.

Por ejemplo, el widget Row permite colocar a sus hijos en dirección horizontal, mientras que el widget Column permite colocar a sus hijos en dirección vertical. Al componer Fila y Columna , se pueden construir widgets con cualquier nivel de complejidad.

Aprendamos algunos de los widgets de uso frecuente en esta sección.

  • Row - Permite disponer sus hijos de forma horizontal.

  • Column - Permite disponer sus hijos de forma vertical.

  • ListView - Permite ordenar sus hijos como lista.

  • GridView - Permite disponer sus hijos como galería.

  • Expanded - Se utiliza para hacer que los hijos del widget Fila y Columna ocupen el máximo área posible.

  • Table - Widget basado en tablas.

  • Flow - Widget basado en flujo.

  • Stack - Widget basado en pila.

Aplicación de diseño avanzado

En esta sección, aprendamos cómo crear una interfaz de usuario compleja de listado de productos con diseño personalizado utilizando widgets de diseño de hijos únicos y múltiples.

Para ello, siga la secuencia que se indica a continuación:

  • Cree una nueva aplicación Flutter en Android Studio, product_layout_app .

  • Reemplace el código main.dart con el siguiente código:

import 'package:flutter/material.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 Demo', theme: ThemeData( 
         primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page'),
      ); 
   } 
} 
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
      
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),), 
         body: Center(child: Text( 'Hello World', )), 
      ); 
   }
}
  • Here,

  • Hemos creado el widget MyHomePage extendiendo StatelessWidget en lugar del StatefulWidget predeterminado y luego eliminamos el código relevante.

  • Ahora, cree un nuevo widget, ProductBox de acuerdo con el diseño especificado como se muestra a continuación:

  • El código de ProductBox es el siguiente.

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) 
      : super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 

   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), height: 120,  child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
                  Image.asset("assets/appimages/" +image), Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                              
                              Text(this.name, style: TextStyle(fontWeight: 
                                 FontWeight.bold)), Text(this.description), 
                              Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}
  • Tenga en cuenta lo siguiente en el código:

  • ProductBox ha utilizado cuatro argumentos como se especifica a continuación:

    • name - Nombre del producto

    • descripción - descripción del producto

    • precio - Precio del producto

    • imagen - Imagen del producto

  • ProductBox utiliza siete widgets integrados como se especifica a continuación:

    • Container
    • Expanded
    • Row
    • Column
    • Card
    • Text
    • Image
  • ProductBox está diseñado utilizando el widget mencionado anteriormente. La disposición o jerarquía del widget se especifica en el diagrama que se muestra a continuación:

  • Ahora, coloque una imagen ficticia (ver a continuación) para obtener información del producto en la carpeta de activos de la aplicación y configure la carpeta de activos en el archivo pubspec.yaml como se muestra a continuación:

assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png

iPhone.png

Pixel.png

Laptop.png

Tablet.png

Pendrive.png

Floppy.png

Finalmente, use el widget ProductBox en el widget MyHomePage como se especifica a continuación:

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title:Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget> [
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
  • Aquí, hemos utilizado ProductBox como elementos secundarios del widget ListView .

  • El código completo (main.dart) de la aplicación de diseño del producto (product_layout_app) es el siguiente:

import 'package:flutter/material.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 Demo', theme: ThemeData(
            primarySwatch: Colors.blue,
         ), 
         home: MyHomePage(title: 'Product layout demo home page'), 
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( 
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[ 
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox( 
                  name: "Pixel",    
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox( 
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 120, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column(    
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ),
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}

El resultado final de la aplicación es el siguiente:

Los gestos son principalmente una forma para que un usuario interactúe con una aplicación móvil (o cualquier dispositivo táctil). Los gestos se definen generalmente como cualquier acción / movimiento físico de un usuario con la intención de activar un control específico del dispositivo móvil. Los gestos son tan simples como tocar la pantalla del dispositivo móvil para acciones más complejas utilizadas en aplicaciones de juegos.

Algunos de los gestos más utilizados se mencionan aquí:

  • Tap - Tocar la superficie del dispositivo con la yema del dedo durante un período breve y luego soltar la yema del dedo.

  • Double Tap - Tocando dos veces en poco tiempo.

  • Drag - Tocar la superficie del dispositivo con la yema del dedo y luego mover la yema del dedo de manera constante y finalmente soltar la yema del dedo.

  • Flick - Similar a arrastrar, pero haciéndolo más rápido.

  • Pinch - Pellizcar la superficie del dispositivo con dos dedos.

  • Spread/Zoom - Lo contrario de pellizcar.

  • Panning - Tocar la superficie del dispositivo con la yema del dedo y moverlo en cualquier dirección sin soltar la yema del dedo.

Flutter proporciona un excelente soporte para todo tipo de gestos a través de su widget exclusivo, GestureDetector. GestureDetector es un widget no visual que se utiliza principalmente para detectar el gesto del usuario. Para identificar un gesto dirigido a un widget, el widget se puede colocar dentro del widget GestureDetector. GestureDetector capturará el gesto y enviará múltiples eventos basados ​​en el gesto.

Algunos de los gestos y los eventos correspondientes se dan a continuación:

  • Tap
    • onTapDown
    • onTapUp
    • onTap
    • onTapCancel
  • Doble toque
    • onDoubleTap
  • Pulsación larga
    • onLongPress
  • Arrastre vertical
    • onVerticalDragStart
    • onVerticalDragUpdate
    • onVerticalDragEnd
  • Arrastre horizontal
    • onHorizontalDragStart
    • onHorizontalDragUpdate
    • onHorizontalDragEnd
  • Pan
    • onPanStart
    • onPanUpdate
    • onPanEnd

Ahora, modifiquemos la aplicación Hola mundo para incluir la función de detección de gestos e intentemos comprender el concepto.

  • Cambie el contenido del cuerpo del widget MyHomePage como se muestra a continuación:

body: Center( 
   child: GestureDetector( 
      onTap: () { 
         _showDialog(context); 
      }, 
      child: Text( 'Hello World', ) 
   ) 
),
  • Observe que aquí hemos colocado el widget GestureDetector encima del widget Text en la jerarquía de widgets, capturamos el evento onTap y finalmente mostramos una ventana de diálogo.

  • Implemente la función * _showDialog * para presentar un diálogo cuando el usuario presiona el mensaje de hola mundo . Utiliza el widget genérico showDialog y AlertDialog para crear un nuevo widget de diálogo. El código se muestra a continuación:

// user defined function void _showDialog(BuildContext context) { 
   // flutter defined function 
   showDialog( 
      context: context, builder: (BuildContext context) { 
         // return object of type Dialog
         return AlertDialog( 
            title: new Text("Message"), 
            content: new Text("Hello World"),   
            actions: <Widget>[ 
               new FlatButton( 
                  child: new Text("Close"),  
                  onPressed: () {   
                     Navigator.of(context).pop();  
                  }, 
               ), 
            ], 
         ); 
      }, 
   ); 
}
  • La aplicación se recargará en el dispositivo usando la función Hot Reload. Ahora, simplemente haga clic en el mensaje, Hola mundo y mostrará el cuadro de diálogo de la siguiente manera:

  • Ahora, cierre el cuadro de diálogo haciendo clic en la opción cerrar en el cuadro de diálogo.

  • El código completo (main.dart) es el siguiente:

import 'package:flutter/material.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: 'Hello World Demo Application', 
         theme: ThemeData( primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   // user defined function 
   void _showDialog(BuildContext context) { 
      // flutter defined function showDialog( 
         context: context, builder: (BuildContext context) { 
            // return object of type Dialog return AlertDialog(
               title: new Text("Message"), 
               content: new Text("Hello World"),   
               actions: <Widget>[
                  new FlatButton(
                     child: new Text("Close"), 
                     onPressed: () {   
                        Navigator.of(context).pop();  
                     }, 
                  ), 
               ],
            );
         },
      );
   }
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center(
            child: GestureDetector( 
               onTap: () {
                  _showDialog(context);
               },
            child: Text( 'Hello World', )
            )
         ),
      );
   }
}

Finalmente, Flutter también proporciona un mecanismo de detección de gestos de bajo nivel a través del widget Listener . Detectará todas las interacciones del usuario y luego enviará los siguientes eventos:

  • PointerDownEvent
  • PointerMoveEvent
  • PointerUpEvent
  • PointerCancelEvent

Flutter también proporciona un pequeño conjunto de widgets para realizar gestos específicos y avanzados. Los widgets se enumeran a continuación:

  • Dismissible - Soporta gestos rápidos para cerrar el widget.

  • Draggable - Soporta gestos de arrastre para mover el widget.

  • LongPressDraggable - Admite el gesto de arrastrar para mover un widget, cuando su widget principal también se puede arrastrar.

  • DragTarget- Acepta cualquier widget arrastrable

  • IgnorePointer - Oculta el widget y sus hijos del proceso de detección de gestos.

  • AbsorbPointer - Detiene el proceso de detección de gestos en sí, por lo que cualquier widget superpuesto tampoco puede participar en el proceso de detección de gestos y, por lo tanto, no se genera ningún evento.

  • Scrollable - Soporte de desplazamiento del contenido disponible dentro del widget.

La gestión del estado en una aplicación es uno de los procesos más importantes y necesarios en el ciclo de vida de una aplicación.

Consideremos una aplicación de carrito de compras simple.

  • El usuario iniciará sesión con sus credenciales en la aplicación.

  • Una vez que el usuario ha iniciado sesión, la aplicación debe conservar los detalles del usuario registrado en toda la pantalla.

  • Una vez más, cuando el usuario selecciona un producto y lo guarda en un carrito, la información del carrito debe persistir entre las páginas hasta que el usuario revisa el carrito.

  • La información del usuario y su carrito en cualquier instancia se denomina estado de la aplicación en esa instancia.

La gestión de un estado se puede dividir en dos categorías según la duración de un estado en particular en una aplicación.

  • Ephemeral- Dura unos segundos como el estado actual de una animación o una sola página como la calificación actual de un producto. Flutter lo admite a través de StatefulWidget.

  • app state- Por último para toda la aplicación, como los detalles del usuario registrado, la información del carrito, etc., Flutter lo admite a través de scoped_model.

Navegación y enrutamiento

En cualquier aplicación, navegar de una página / pantalla a otra define el flujo de trabajo de la aplicación. La forma en que se maneja la navegación de una aplicación se denomina Enrutamiento. Flutter proporciona una clase de enrutamiento básica, MaterialPageRoute, y dos métodos, Navigator.push y Navigator.pop, para definir el flujo de trabajo de una aplicación.

MaterialPageRoute

MaterialPageRoute es un widget que se utiliza para representar su interfaz de usuario reemplazando toda la pantalla con una animación específica de la plataforma.

MaterialPageRoute(builder: (context) => Widget())

Aquí, el constructor aceptará una función para construir su contenido proporcionando el contexto actual de la aplicación.

Navigation.push

Navigation.push se usa para navegar a una nueva pantalla usando el widget MaterialPageRoute.

Navigator.push( context, MaterialPageRoute(builder: (context) => Widget()), );

Navigation.pop

Navigation.pop se utiliza para navegar a la pantalla anterior.

Navigator.pop(context);

Creemos una nueva aplicación para comprender mejor el concepto de navegación.

Cree una nueva aplicación Flutter en Android Studio, product_nav_app

  • Copie la carpeta de activos de product_nav_app a product_state_app y agregue activos dentro del archivo pubspec.yaml.

flutter:
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • Reemplace el código de inicio predeterminado (main.dart) con nuestro código de inicio.

import 'package:flutter/material.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 Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Product state demo home page'
         ),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title), 
         ), 
         body: Center(
            child: Text('Hello World',)
         ), 
      ); 
   } 
}
  • Creemos una clase de producto para organizar la información del producto.

class Product { 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
}
  • Escribamos un método getProducts en la clase Product para generar nuestros registros de productos ficticios.

static List<Product> getProducts() {
   List<Product> items = <Product>[]; 
   
   items.add(
      Product( 
         "Pixel", 
         "Pixel is the most feature-full phone ever", 800, 
         "pixel.png"
      )
   ); 
   items.add(
      Product(
         "Laptop", 
         "Laptop is most productive development tool", 
         2000, "
         laptop.png"
      )
   ); 
   items.add(
      Product( 
         "Tablet", 
         "Tablet is the most useful device ever for meeting", 
         1500, 
         "tablet.png"
      )
   ); 
   items.add(
      Product( 
         "Pendrive", 
         "Pendrive is useful storage medium",
         100, 
         "pendrive.png"
      )
   ); 
   items.add(
      Product( 
         "Floppy Drive", 
         "Floppy drive is useful rescue storage medium", 
         20, 
         "floppy.png"
      )
   ); 
   return items; 
}
import product.dart in main.dart
import 'Product.dart';
  • Incluyamos nuestro nuevo widget, RatingBox.

class RatingBox extends StatefulWidget {
   @override 
   _RatingBoxState createState() =>_RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> {
   int _rating = 0; 
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   } 
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   }
   void _setRatingAsThree() {
      setState(() {
         _rating = 3;
      });
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 2? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   }
}
  • Modifiquemos nuestro widget ProductBox para que funcione con nuestra nueva clase de producto.

class ProductBox extends StatelessWidget {    
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), 
                        child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[
                              Text(this.item.name, 
                              style: TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  )
               ]
            ), 
         )
      ); 
   }
}

Reescribamos nuestro widget MyHomePage para que funcione con el modelo de Producto y para enumerar todos los productos usando ListView.

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( appBar: AppBar(title: Text("Product Navigation")), 
      body: ListView.builder( 
         itemCount: items.length, 
         itemBuilder: (context, index) {
            return GestureDetector( 
               child: ProductBox(item: items[index]), 
               onTap: () { 
                  Navigator.push( 
                     context, MaterialPageRoute( 
                        builder: (context) => ProductPage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      )); 
   } 
}

Aquí, hemos utilizado MaterialPageRoute para navegar a la página de detalles del producto.

  • Ahora, agreguemos ProductPage para mostrar los detalles del producto.

class ProductPage extends StatelessWidget { 
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container(
               padding: EdgeInsets.all(0), 
               child: Column(
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded(
                        child: Container(
                           padding: EdgeInsets.all(5), 
                           child: Column(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[
                                 Text(
                                    this.item.name, style: TextStyle(
                                       fontWeight: FontWeight.bold
                                    )
                                 ), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(),
                              ], 
                           )
                        )
                     )
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}

El código completo de la aplicación es el siguiente:

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class Product {
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
   
   static List<Product> getProducts() {
      List<Product> items = <Product>[]; 
      items.add(
         Product(
            "Pixel", 
            "Pixel is the most featureful phone ever", 
            800, 
            "pixel.png"
         )
      );
      items.add(
         Product(
            "Laptop", 
            "Laptop is most productive development tool", 
            2000, 
            "laptop.png"
         )
      ); 
      items.add(
         Product(
            "Tablet", 
            "Tablet is the most useful device ever for meeting", 
            1500, 
            "tablet.png"
         )
      ); 
      items.add(
         Product( 
            "Pendrive", 
            "iPhone is the stylist phone ever", 
            100, 
            "pendrive.png"
         )
      ); 
      items.add(
         Product(
            "Floppy Drive", 
            "iPhone is the stylist phone ever", 
            20, 
            "floppy.png"
         )
      ); 
      items.add(
         Product(
            "iPhone", 
            "iPhone is the stylist phone ever", 
            1000, 
            "iphone.png"
         )
      ); 
      return items; 
   }
}
class MyApp extends StatelessWidget {
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Product Navigation demo home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Navigation")), 
         body: ListView.builder( 
            itemCount: items.length, 
            itemBuilder: (context, index) { 
               return GestureDetector( 
                  child: ProductBox(item: items[index]), 
                  onTap: () { 
                     Navigator.push( 
                        context, 
                        MaterialPageRoute( 
                           builder: (context) => ProductPage(item: items[index]), 
                        ), 
                     ); 
                  }, 
               ); 
            }, 
         )
      ); 
   }
} 
class ProductPage extends StatelessWidget {
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container( 
               padding: EdgeInsets.all(0), 
               child: Column( 
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[ 
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded( 
                        child: Container( 
                           padding: EdgeInsets.all(5), 
                           child: Column( 
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                                 Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(), 
                              ], 
                           )
                        )
                     ) 
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}
class RatingBox extends StatefulWidget { 
   @override 
   _RatingBoxState createState() => _RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> { 
   int _rating = 0;
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   }
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   } 
   void _setRatingAsThree() { 
      setState(() {
         _rating = 3; 
      }); 
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1 ? Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton( 
                  icon: (
                     _rating >= 2 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     )
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   } 
} 
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  ) 
               ]
            ), 
         )
      ); 
   } 
}

Ejecute la aplicación y haga clic en cualquiera de los elementos del producto. Mostrará la página de detalles relevantes. Podemos movernos a la página de inicio haciendo clic en el botón Atrás. La página de lista de productos y la página de detalles del producto de la aplicación se muestran a continuación:

La animación es un procedimiento complejo en cualquier aplicación móvil. A pesar de su complejidad, la animación mejora la experiencia del usuario a un nuevo nivel y proporciona una rica interacción con el usuario. Debido a su riqueza, la animación se convierte en una parte integral de las aplicaciones móviles modernas. El marco Flutter reconoce la importancia de la animación y proporciona un marco simple e intuitivo para desarrollar todo tipo de animaciones.

Introducción

La animación es un proceso de mostrar una serie de imágenes / imágenes en un orden particular dentro de una duración específica para dar una ilusión de movimiento. Los aspectos más importantes de la animación son los siguientes:

  • La animación tiene dos valores distintos: valor inicial y valor final. La animación comienza desde el valor de Inicio y pasa por una serie de valores intermedios y finalmente termina en los valores de Fin. Por ejemplo, para animar un widget para que desaparezca, el valor inicial será la opacidad total y el valor final será la opacidad cero.

  • Los valores intermedios pueden ser de naturaleza lineal o no lineal (curva) y se puede configurar. Comprenda que la animación funciona como está configurada. Cada configuración proporciona una sensación diferente a la animación. Por ejemplo, el desvanecimiento de un widget será de naturaleza lineal, mientras que el rebote de una pelota será de naturaleza no lineal.

  • La duración del proceso de animación afecta la velocidad (lentitud o rapidez) de la animación.

  • La capacidad de controlar el proceso de animación como iniciar la animación, detener la animación, repetir la animación para establecer el número de veces, invertir el proceso de animación, etc.

  • En Flutter, el sistema de animación no realiza ninguna animación real. En cambio, proporciona solo los valores necesarios en cada fotograma para representar las imágenes.

Clases basadas en animación

El sistema de animación Flutter se basa en objetos de animación. Las clases principales de animación y su uso son las siguientes:

Animación

Genera valores interpolados entre dos números durante un período determinado. Las clases de animación más comunes son:

  • Animation<double> - interpolar valores entre dos números decimales

  • Animation<Color> - interpolar colores entre dos colores

  • Animation<Size> - interpolar tamaños entre dos tamaños

  • AnimationController- Objeto de animación especial para controlar la propia animación. Genera nuevos valores siempre que la aplicación esté lista para un nuevo marco. Admite animación basada en líneas lineales y el valor comienza de 0.0 a 1.0

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);

Aquí, el controlador controla la animación y la opción de duración controla la duración del proceso de animación. vsync es una opción especial que se utiliza para optimizar el recurso utilizado en la animación.

Animación Curvada

Similar a AnimationController pero admite animación no lineal. CurvedAnimation se puede usar junto con el objeto Animation como se muestra a continuación:

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)

Tween <T>

Derivado de Animatable <T> y utilizado para generar números entre dos números que no sean 0 y 1. Se puede utilizar junto con el objeto Animation utilizando el método animado y pasando el objeto Animation real.

AnimationController controller = AnimationController( 
   duration: const Duration(milliseconds: 1000), 
vsync: this); Animation<int> customTween = IntTween(
   begin: 0, end: 255).animate(controller);
  • Tween también se puede usar junto con CurvedAnimation como se muestra a continuación:

AnimationController controller = AnimationController(
   duration: const Duration(milliseconds: 500), vsync: this); 
final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut); 
Animation<int> customTween = IntTween(begin: 0, end: 255).animate(curve);

Aquí, el controlador es el controlador de animación real. La curva proporciona el tipo de no linealidad y customTween proporciona un rango personalizado de 0 a 255.

Flujo de trabajo de la animación Flutter

El flujo de trabajo de la animación es el siguiente:

  • Defina e inicie el controlador de animación en initState del StatefulWidget.

AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = Tween<double>(begin: 0, end: 300).animate(controller); 
controller.forward();
  • Agregue un oyente basado en animación, addListener para cambiar el estado del widget.

animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() {
   setState(() { 
      // The state that has changed here is the animation object’s value. 
   }); 
});
  • Los widgets integrados, AnimatedWidget y AnimatedBuilder se pueden utilizar para omitir este proceso. Ambos widgets aceptan el objeto de animación y obtienen los valores actuales necesarios para la animación.

  • Obtenga los valores de la animación durante el proceso de construcción del widget y luego aplíquelos para el ancho, alto o cualquier propiedad relevante en lugar del valor original.

child: Container( 
   height: animation.value, 
   width: animation.value, 
   child: <Widget>, 
)

Aplicación de trabajo

Escribamos una aplicación sencilla basada en animación para comprender el concepto de animación en el marco de Flutter.

  • Cree una nueva aplicación Flutter en Android Studio, product_animation_app.

  • Copie la carpeta de activos de product_nav_app a product_animation_app y agregue activos dentro del archivo pubspec.yaml.

flutter: 
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • Elimina el código de inicio predeterminado (main.dart).

  • Agregue importación y función principal básica.

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp());
  • Cree el widget MyApp derivado de StatefulWidgtet.

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
}
  • Cree el widget _MyAppState e implemente initState y elimínelo además del método de compilación predeterminado.

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin { 
   Animation<double> animation; 
   AnimationController controller; 
   @override void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this
      ); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp(
         title: 'Flutter Demo',
         theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,)
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose();
   }
}

Aquí,

  • En el método initState, hemos creado un objeto controlador de animación (controlador), un objeto de animación (animación) y comenzamos la animación usando controller.forward.

  • En el método de eliminación, hemos eliminado el objeto controlador de animación (controlador).

  • En el método de compilación, envíe la animación al widget MyHomePage a través del constructor. Ahora, el widget MyHomePage puede usar el objeto de animación para animar su contenido.

  • Ahora, agregue el widget ProductBox

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image})
      : super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row( 
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.name, style: 
                                 TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.description), 
                                 Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      ); 
   }
}
  • Cree un nuevo widget, MyAnimatedWidget para hacer una animación de fundido simple usando opacidad.

class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
      
   final Widget child; 
   final Animation<double> animation; 
   
   Widget build(BuildContext context) => Center( 
   child: AnimatedBuilder(
      animation: animation, 
      builder: (context, child) => Container( 
         child: Opacity(opacity: animation.value, child: child), 
      ), 
      child: child), 
   ); 
}
  • Aquí, hemos utilizado AniateBuilder para hacer nuestra animación. AnimatedBuilder es un widget que construye su contenido mientras hace la animación al mismo tiempo. Acepta un objeto de animación para obtener el valor de animación actual. Hemos utilizado el valor de animación, animation.value para establecer la opacidad del widget secundario. En efecto, el widget animará el widget secundario usando el concepto de opacidad.

  • Finalmente, cree el widget MyHomePage y use el objeto de animación para animar cualquiera de su contenido.

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title, this.animation}) : super(key: key); 
   
   final String title; 
   final Animation<double> 
   animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")),body: ListView(
            shrinkWrap: true,
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), opacity: animation
               ), 
               MyAnimatedWidget(child: ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), animation: animation), 
               ProductBox(
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ),
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ),
            ],
         )
      );
   }
}

Aquí, hemos utilizado FadeAnimation y MyAnimationWidget para animar los dos primeros elementos de la lista. FadeAnimation es una clase de animación incorporada, que usamos para animar a su hijo usando el concepto de opacidad.

  • El código completo es el siguiente:

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
} 
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
   Animation<double> animation; 
   AnimationController controller; 
   
   @override 
   void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp( 
         title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,) 
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose(); 
   } 
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title, this.animation}): super(key: key);
   final String title; 
   final Animation<double> animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), 
                  opacity: animation
               ), 
               MyAnimatedWidget(
                  child: ProductBox( 
                     name: "Pixel", 
                     description: "Pixel is the most featureful phone ever", 
                     price: 800, 
                     image: "pixel.png"
                  ), 
                  animation: animation
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet",
                  description: "Tablet is the most useful device ever for meeting",
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ], 
         )
      ); 
   } 
} 
class ProductBox extends StatelessWidget { 
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded(
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ), 
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  ) 
               ]
            )
         )
      ); 
   } 
}
class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
   final Widget child; 
   final Animation<double> animation; 
 
   Widget build(BuildContext context) => Center( 
      child: AnimatedBuilder(
         animation: animation, 
         builder: (context, child) => Container( 
            child: Opacity(opacity: animation.value, child: child), 
         ), 
         child: child
      ), 
   ); 
}
  • Compile y ejecute la aplicación para ver los resultados. La versión inicial y final de la aplicación es la siguiente:

Flutter proporciona un marco general para acceder a funciones específicas de la plataforma. Esto permite al desarrollador ampliar la funcionalidad del marco Flutter utilizando código específico de la plataforma. Se puede acceder fácilmente a la funcionalidad específica de la plataforma, como cámara, nivel de batería, navegador, etc., a través del marco.

La idea general de acceder al código específico de la plataforma es a través de un protocolo de mensajería simple. El código Flutter, el cliente y el código de la plataforma y el host se vinculan a un canal de mensajes común. El cliente envía un mensaje al anfitrión a través del canal de mensajes. El Anfitrión escucha en el Canal de Mensajes, recibe el mensaje y hace la funcionalidad necesaria y finalmente, devuelve el resultado al Cliente a través del Canal de Mensajes.

La arquitectura de código específica de la plataforma se muestra en el diagrama de bloques que se muestra a continuación

El protocolo de mensajería utiliza un códec de mensaje estándar (clase StandardMessageCodec) que admite la serialización binaria de valores similares a JSON como números, cadenas, booleanos, etc. La serialización y deserialización funciona de forma transparente entre el cliente y el host.

Escribamos una aplicación simple para abrir un navegador usando Android SDK y entendamos cómo

  • Cree una nueva aplicación Flutter en Android Studio, flutter_browser_app

  • Reemplace el código main.dart con el siguiente código:

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Flutter Demo Home Page'),
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton( 
               child: Text('Open Browser'), 
               onPressed: null, 
            ), 
         ), 
      ); 
   }
}
  • Aquí, hemos creado un nuevo botón para abrir el navegador y establecer su método onPressed como nulo.

  • Ahora, importe los siguientes paquetes:

import 'dart:async'; 
import 'package:flutter/services.dart';
  • Aquí, services.dart incluye la funcionalidad para invocar código específico de la plataforma.

  • Cree un nuevo canal de mensajes en el widget MyHomePage.

static const platform = const 
MethodChannel('flutterapp.tutorialspoint.com/browser');
  • Escriba un método, _openBrowser para invocar el método específico de la plataforma, el método openBrowser a través del canal de mensajes.

Future<void> _openBrowser() async { 
   try {
      final int result = await platform.invokeMethod(
         'openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         }
      ); 
   } 
   on PlatformException catch (e) { 
      // Unable to open the browser 
      print(e); 
   }
}

Aquí, hemos utilizado platform.invokeMethod para invocar openBrowser (explicado en los próximos pasos). openBrowser tiene un argumento, url para abrir una URL específica.

  • Cambie el valor de la propiedad onPressed de RaisedButton de nulo a _openBrowser.

onPressed: _openBrowser,
  • Abra MainActivity.java (dentro de la carpeta de Android) e importe la biblioteca requerida -

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugins.GeneratedPluginRegistrant;
  • Escriba un método, openBrowser para abrir un navegador

private void openBrowser(MethodCall call, Result result, String url) { 
   Activity activity = this; 
   if (activity == null) { 
      result.error("ACTIVITY_NOT_AVAILABLE", 
      "Browser cannot be opened without foreground 
      activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • Ahora, establezca el nombre del canal en la clase MainActivity -

private static final String CHANNEL = "flutterapp.tutorialspoint.com/browser";
  • Escriba el código específico de Android para configurar el manejo de mensajes en el método onCreate -

new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( 
   new MethodCallHandler() { 
   @Override 
   public void onMethodCall(MethodCall call, Result result) { 
      String url = call.argument("url"); 
      if (call.method.equals("openBrowser")) {
         openBrowser(call, result, url); 
      } else { 
         result.notImplemented(); 
      } 
   } 
});

Aquí, hemos creado un canal de mensajes usando la clase MethodChannel y usamos la clase MethodCallHandler para manejar el mensaje. onMethodCall es el método real responsable de llamar al código específico de la plataforma correcta al verificar el mensaje. El método onMethodCall extrae la URL del mensaje y luego invoca openBrowser solo cuando la llamada al método es openBrowser. De lo contrario, devuelve el método notImplemented.

El código fuente completo de la aplicación es el siguiente:

main.dart

MainActivity.java

package com.tutorialspoint.flutterapp.flutter_browser_app; 

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 
import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugins.GeneratedPluginRegistrant; 

public class MainActivity extends FlutterActivity { 
   private static final String CHANNEL = "flutterapp.tutorialspoint.com/browser"; 
   @Override 
   protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      GeneratedPluginRegistrant.registerWith(this); 
      new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
         new MethodCallHandler() {
            @Override 
            public void onMethodCall(MethodCall call, Result result) {
               String url = call.argument("url"); 
               if (call.method.equals("openBrowser")) { 
                  openBrowser(call, result, url); 
               } else { 
                  result.notImplemented(); 
               }
            }
         }
      ); 
   }
   private void openBrowser(MethodCall call, Result result, String url) {
      Activity activity = this; if (activity == null) {
         result.error(
            "ACTIVITY_NOT_AVAILABLE", "Browser cannot be opened without foreground activity", null
         ); 
         return; 
      } 
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   }
}

main.dart

import 'package:flutter/material.dart'; 
import 'dart:async'; 
import 'package:flutter/services.dart'; 

void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget {
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   static const platform = const MethodChannel('flutterapp.tutorialspoint.com/browser'); 
   Future<void> _openBrowser() async {
      try {
         final int result = await platform.invokeMethod('openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         });
      }
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      } 
   }
   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar( 
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton( 
               child: Text('Open Browser'), 
               onPressed: _openBrowser, 
            ), 
         ),
      );
   }
}

Ejecute la aplicación y haga clic en el botón Abrir navegador y podrá ver que se inicia el navegador. La aplicación del navegador - La página de inicio es como se muestra en la captura de pantalla aquí -

El acceso al código específico de iOS es similar al de la plataforma Android, excepto que utiliza lenguajes específicos de iOS: Objective-C o Swift y SDK de iOS. De lo contrario, el concepto es el mismo que el de la plataforma Android.

Escribamos también la misma aplicación que en el capítulo anterior para la plataforma iOS.

  • Creemos una nueva aplicación en Android Studio (macOS), flutter_browser_ios_app

  • Siga los pasos 2 a 6 como en el capítulo anterior.

  • Inicie XCode y haga clic en File → Open

  • Elija el proyecto xcode en el directorio ios de nuestro proyecto flutter.

  • Abra AppDelegate.m debajo Runner → Runner path. Contiene el siguiente código:

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
      // [GeneratedPluginRegistrant registerWithRegistry:self];
      // Override point for customization after application launch.
      return [super application:application didFinishLaunchingWithOptions:launchOptions];
   } 
@end
  • Hemos agregado un método, openBrowser para abrir el navegador con la URL especificada. Acepta un solo argumento, url.

- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
}
  • En el método didFinishLaunchingWithOptions, busque el controlador y configúrelo en la variable del controlador.

FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
  • En el método didFinishLaunchingWithOptions, configure el canal del navegador como flutterapp.tutorialspoint.com/browse -

FlutterMethodChannel* browserChannel = [
   FlutterMethodChannel methodChannelWithName:
   @"flutterapp.tutorialspoint.com/browser" binaryMessenger:controller];
  • Cree una variable, débilSelf y establezca la clase actual -

__weak typeof(self) weakSelf = self;
  • Ahora, implemente setMethodCallHandler. Llame a openBrowser haciendo coincidir call.method. Obtén la URL invocando call.arguments y pásala mientras llamas a openBrowser.

[browserChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
   if ([@"openBrowser" isEqualToString:call.method]) { 
      NSString *url = call.arguments[@"url"];   
      [weakSelf openBrowser:url]; 
   } else { result(FlutterMethodNotImplemented); } 
}];
  • El código completo es el siguiente:

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application 
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   
   // custom code starts 
   FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; 
   FlutterMethodChannel* browserChannel = [
      FlutterMethodChannel methodChannelWithName:
      @"flutterapp.tutorialspoint.com /browser" binaryMessenger:controller]; 
   
   __weak typeof(self) weakSelf = self; 
   [browserChannel setMethodCallHandler:^(
      FlutterMethodCall* call, FlutterResult result) { 
      
      if ([@"openBrowser" isEqualToString:call.method]) { 
         NSString *url = call.arguments[@"url"];
         [weakSelf openBrowser:url]; 
      } else { result(FlutterMethodNotImplemented); } 
   }]; 
   // custom code ends 
   [GeneratedPluginRegistrant registerWithRegistry:self]; 
   
   // Override point for customization after application launch. 
   return [super application:application didFinishLaunchingWithOptions:launchOptions]; 
}
- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
} 
@end
  • Configuración de proyecto abierto.

  • Ir Capabilities y habilitar Background Modes.

  • Añadir *Background fetch y Remote Notification**.

  • Ahora, ejecute la aplicación. Funciona de manera similar a la versión de Android, pero se abrirá el navegador Safari en lugar de Chrome.

La forma de Dart de organizar y compartir un conjunto de funcionalidades es a través de Package. Dart Package es simplemente bibliotecas o módulos que se pueden compartir. En general, el paquete Dart es el mismo que el de la aplicación Dart, excepto que el paquete Dart no tiene un punto de entrada de la aplicación, principal.

La estructura general del paquete (considere un paquete de demostración, my_demo_package) es la siguiente:

  • lib/src/* - Archivos de código privados de Dart.

  • lib/my_demo_package.dart- Archivo de código principal de Dart. Se puede importar a una aplicación como:

import 'package:my_demo_package/my_demo_package.dart'
  • Se puede exportar otro archivo de código privado al archivo de código principal (my_demo_package.dart), si es necesario, como se muestra a continuación:

export src/my_private_code.dart
  • lib/*- Cualquier cantidad de archivos de código Dart organizados en cualquier estructura de carpeta personalizada. Se puede acceder al código como,

import 'package:my_demo_package/custom_folder/custom_file.dart'
  • pubspec.yaml - Especificación del proyecto, igual que la de la aplicación,

Todos los archivos de código de Dart en el paquete son simplemente clases de Dart y no tienen ningún requisito especial para que un código de Dart lo incluya en un paquete.

Tipos de paquetes

Dado que los paquetes de Dart son básicamente una pequeña colección de funciones similares, se pueden clasificar en función de su funcionalidad.

Paquete de dardos

Código Dart genérico, que se puede utilizar tanto en entornos web como móviles. Por ejemplo, english_words es uno de esos paquetes que contiene alrededor de 5000 palabras y tiene funciones básicas de utilidad como sustantivos (enumerar sustantivos en inglés), sílabas (especificar el número de sílabas en una palabra.

Paquete Flutter

Código genérico de Dart, que depende del marco de Flutter y solo se puede usar en un entorno móvil. Por ejemplo, fluro es un enrutador personalizado para flutter. Depende del marco de Flutter.

Complemento Flutter

Código genérico de Dart, que depende del marco de Flutter y del código de la plataforma subyacente (SDK de Android o SDK de iOS). Por ejemplo, la cámara es un complemento para interactuar con la cámara del dispositivo. Depende del marco Flutter y del marco subyacente para acceder a la cámara.

Usando un paquete de dardos

Los paquetes de Dart se alojan y publican en el servidor en vivo, https://pub.dartlang.org.Además, Flutter proporciona una herramienta simple, pub para administrar paquetes de Dart en la aplicación. Los pasos necesarios para usar como paquete son los siguientes:

  • Incluya el nombre del paquete y la versión necesaria en pubspec.yaml como se muestra a continuación:

dependencies: english_words: ^3.1.5
  • El número de versión más reciente se puede encontrar consultando el servidor en línea.

  • Instale el paquete en la aplicación usando el siguiente comando:

flutter packages get
  • Mientras desarrolla en Android Studio, Android Studio detecta cualquier cambio en pubspec.yaml y muestra una alerta de paquete de Android Studio al desarrollador como se muestra a continuación:

  • Los paquetes de Dart se pueden instalar o actualizar en Android Studio usando las opciones del menú.

  • Importe el archivo necesario usando el comando que se muestra a continuación y comience a trabajar -

import 'package:english_words/english_words.dart';
  • Utilice cualquier método disponible en el paquete,

nouns.take(50).forEach(print);
  • Aquí, hemos utilizado la función de sustantivos para obtener e imprimir las 50 palabras principales.

Desarrollar un paquete de complementos de Flutter

Desarrollar un complemento de Flutter es similar a desarrollar una aplicación Dart o un paquete Dart. La única excepción es que el complemento utilizará la API del sistema (Android o iOS) para obtener la funcionalidad específica de la plataforma requerida.

Como ya hemos aprendido cómo acceder al código de la plataforma en los capítulos anteriores, desarrollemos un complemento simple, my_browser, para comprender el proceso de desarrollo del complemento. La funcionalidad del complemento my_browser es permitir que la aplicación abra el sitio web dado en el navegador específico de la plataforma.

  • Inicie Android Studio.

  • Hacer clic File → New Flutter Project y seleccione la opción Flutter Plugin.

  • Puede ver una ventana de selección de complemento de Flutter como se muestra aquí:

  • Ingrese my_browser como nombre del proyecto y haga clic en Siguiente.

  • Ingrese el nombre del complemento y otros detalles en la ventana como se muestra aquí -

  • Ingrese el dominio de la empresa, flutterpillarlugins.tutorialspoint.com en la ventana que se muestra a continuación y luego haga clic en Finish. Generará un código de inicio para desarrollar nuestro nuevo complemento.

  • Abra el archivo my_browser.dart y escriba un método, openBrowser para invocar el método openBrowser específico de la plataforma.

Future<void> openBrowser(String urlString) async { 
   try {
      final int result = await _channel.invokeMethod(
         'openBrowser', <String, String>{ 'url': urlString }
      );
   }
   on PlatformException catch (e) { 
      // Unable to open the browser print(e); 
   } 
}
  • Abra el archivo MyBrowserPlugin.java e importe las siguientes clases:

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle;
  • Aquí, tenemos que importar la biblioteca necesaria para abrir un navegador desde Android.

  • Agregue una nueva variable privada mRegistrar de tipo Registrar en la clase MyBrowserPlugin.

private final Registrar mRegistrar;
  • Aquí, Registrar se utiliza para obtener información de contexto del código de invocación.

  • Agregue un constructor para configurar Registrar en la clase MyBrowserPlugin.

private MyBrowserPlugin(Registrar registrar) { 
   this.mRegistrar = registrar; 
}
  • Cambie registerWith para incluir nuestro nuevo constructor en la clase MyBrowserPlugin.

public static void registerWith(Registrar registrar) { 
   final MethodChannel channel = new MethodChannel(registrar.messenger(), "my_browser"); 
   MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
   channel.setMethodCallHandler(instance); 
}
  • Cambie onMethodCall para incluir el método openBrowser en la clase MyBrowserPlugin.

@Override 
public void onMethodCall(MethodCall call, Result result) { 
   String url = call.argument("url");
   if (call.method.equals("getPlatformVersion")) { 
      result.success("Android " + android.os.Build.VERSION.RELEASE); 
   } 
   else if (call.method.equals("openBrowser")) { 
      openBrowser(call, result, url); 
   } else { 
      result.notImplemented(); 
   } 
}
  • Escriba el método openBrowser específico de la plataforma para acceder al navegador en la clase MyBrowserPlugin.

private void openBrowser(MethodCall call, Result result, String url) { 
   Activity activity = mRegistrar.activity(); 
   if (activity == null) {
      result.error("ACTIVITY_NOT_AVAILABLE", 
      "Browser cannot be opened without foreground activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • El código fuente completo del complemento my_browser es el siguiente:

my_browser.dart

import 'dart:async'; 
import 'package:flutter/services.dart'; 

class MyBrowser {
   static const MethodChannel _channel = const MethodChannel('my_browser'); 
   static Future<String> get platformVersion async { 
      final String version = await _channel.invokeMethod('getPlatformVersion'); return version; 
   } 
   Future<void> openBrowser(String urlString) async { 
      try {
         final int result = await _channel.invokeMethod(
            'openBrowser', <String, String>{'url': urlString}); 
      } 
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      }
   }
}

MyBrowserPlugin.java

package com.tutorialspoint.flutterplugins.my_browser; 

import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugin.common.PluginRegistry.Registrar; 
import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

/** MyBrowserPlugin */ 
public class MyBrowserPlugin implements MethodCallHandler {
   private final Registrar mRegistrar; 
   private MyBrowserPlugin(Registrar registrar) { 
      this.mRegistrar = registrar; 
   } 
   /** Plugin registration. */
   public static void registerWith(Registrar registrar) {
      final MethodChannel channel = new MethodChannel(
         registrar.messenger(), "my_browser"); 
      MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
      channel.setMethodCallHandler(instance); 
   } 
   @Override 
   public void onMethodCall(MethodCall call, Result result) { 
      String url = call.argument("url"); 
      if (call.method.equals("getPlatformVersion")) { 
         result.success("Android " + android.os.Build.VERSION.RELEASE); 
      } 
      else if (call.method.equals("openBrowser")) { 
         openBrowser(call, result, url); 
      } else { 
         result.notImplemented(); 
      } 
   } 
   private void openBrowser(MethodCall call, Result result, String url) { 
      Activity activity = mRegistrar.activity(); 
      if (activity == null) {
         result.error("ACTIVITY_NOT_AVAILABLE",
            "Browser cannot be opened without foreground activity", null); 
         return; 
      }
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   } 
}
  • Cree un nuevo proyecto, my_browser_plugin_test para probar nuestro complemento recién creado.

  • Abra pubspec.yaml y configure my_browser como una dependencia del complemento.

dependencies: 
   flutter: 
      sdk: flutter 
   my_browser: 
      path: ../my_browser
  • Android Studio alertará de que pubspec.yaml se actualiza como se muestra en la alerta del paquete de Android Studio que se muestra a continuación:

  • Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo configurará correctamente para la aplicación.

  • Abra main.dart e incluya el complemento my_browser como se muestra a continuación:

import 'package:my_browser/my_browser.dart';
  • Llame a la función openBrowser desde el complemento my_browser como se muestra a continuación:

onPressed: () => MyBrowser().openBrowser("https://flutter.dev"),
  • El código completo del main.dart es el siguiente:

import 'package:flutter/material.dart'; 
import 'package:my_browser/my_browser.dart'; 

void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp( 
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      );,
   }
} 
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton(
               child: Text('Open Browser'), 
               onPressed: () => MyBrowser().openBrowser("https://flutter.dev"), 
            ),
         ), 
      ); 
   }
}
  • Ejecute la aplicación y haga clic en el botón Abrir navegador y compruebe que se inicia el navegador. Puede ver una aplicación de navegador - Página de inicio como se muestra en la captura de pantalla que se muestra a continuación -

Puede ver una aplicación del navegador - Pantalla del navegador como se muestra en la captura de pantalla que se muestra a continuación -

  • Print
  •  Agregar notas
  •  Marca esta pagina
  •  Informar error
  •  Suggestions

Guardar Cerrar