Flutter - Tutorial en Español
Flutter - Tutorial en Español
Flutter es un marco de código abierto para crear aplicaciones móviles de alta calidad y alto rendimiento en todos
los sistemas operativos móviles: Android e iOS. Proporciona un SDK simple, potente, eficiente y fácil de entender
para escribir aplicaciones móviles en el propio lenguaje de Google, Dart.
Este tutorial recorre los conceptos básicos del marco Flutter, la instalación de Flutter SDK, la configuración de
Android Studio para desarrollar una aplicación basada en Flutter, la arquitectura de Flutter
framework y desarrollando todo tipo de aplicaciones móviles usando Flutter framework.
Audiencia
Este tutorial está preparado para profesionales que aspiran a hacer carrera en el campo de las aplicaciones
móviles. Este tutorial está destinado a que se sienta cómodo al comenzar con el marco Flutter y sus diversas
funcionalidades.
requisitos previos
Este tutorial está escrito asumiendo que los lectores ya saben qué es un marco y que tienen un conocimiento
sólido sobre la programación orientada a objetos y un conocimiento básico sobre el marco de trabajo de Android
y la programación de Dart.
Si eres un principiante en alguno de estos conceptos, te sugerimos que revises los tutoriales relacionados con
estos primero, antes de comenzar con Flutter.
Todo el contenido y gráficos publicados en este e-book son propiedad de Tutorials Point (I)
privado Ltd. El usuario de este libro electrónico tiene prohibido reutilizar, retener, copiar, distribuir o volver a
publicar cualquier contenido o parte del contenido de este libro electrónico de cualquier manera sin el
consentimiento por escrito del editor.
Nos esforzamos por actualizar los contenidos de nuestro sitio web y los tutoriales de la manera más oportuna y
precisa posible; sin embargo, los contenidos pueden contener inexactitudes o errores. Tutoriales Punto (I) Pvt.
Ltd. no ofrece ninguna garantía con respecto a la precisión, puntualidad o integridad de nuestro sitio
web o su contenido, incluido este tutorial. Si descubre algún error en nuestro sitio web o en este
tutorial, avísenos a [email protected]
I
Machine Translated by Google
Aleteo
Tabla de contenido
Sobre el Tutorial .............................................................. .................................................... ...........................................I
yl
Machine Translated by Google
Aleteo
iii
Machine Translated by Google
Aleteo
IV
Machine Translated by Google
1. Aleteo – Introducción
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/Shift.
Sin embargo, para desarrollar una aplicación compatible con ambos sistemas operativos, necesitamos codificar en dos
idiomas diferentes usando dos marcos diferentes. Para ayudar a superar esta complejidad, existen marcos móviles que
admiten 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 el código en código nativo). Independientemente de su
simplicidad o complejidad, estos marcos siempre tienen muchas desventajas, siendo uno de los principales inconvenientes
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
los widgets están optimizados para el entorno móvil y diseñar la aplicación usando widgets es tan simple como diseñar
HTML.
Para ser específicos, 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 comparará automáticamente (programación reactiva) el estado del widget (antiguo y
nuevo) y renderizará el widget solo con los cambios necesarios en lugar de volver a renderizar todo el widget.
Características de Flutter
1
Machine Translated by Google
Aleteo
Ventajas de Flutter
Flutter viene con widgets hermosos y personalizables para un alto rendimiento y una aplicación móvil
sobresaliente. 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 depósito de paquetes de software que le permite ampliar las capacidades de su
aplicación.
• Los desarrolladores deben escribir una única base de código para ambas aplicaciones (tanto en plataformas
Android como iOS). Es posible que Flutter también se extienda 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.
• Con Flutter, los desarrolladores tienen control total sobre los widgets y su diseño.
• Flutter ofrece excelentes herramientas para desarrolladores, 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 lenguaje (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 se entremezclan. 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 tienen dificultades para elegir
las herramientas de desarrollo adecuadas en un segmento muy poblado.
2
Machine Translated by Google
Aleteo
2. Flutter – Instalación
Instalación en Windows
En esta sección, veamos cómo instalar Flutter SDK y sus requisitos en un sistema Windows.
Paso 3: actualice la ruta del sistema para incluir el directorio flutter bin.
Paso 4: Flutter proporciona una herramienta, flutter doctor para verificar que se cumplan todos los requisitos de
desarrollo de flutter.
médico aleteo
Paso 5: ejecutar el comando anterior analizará el sistema y mostrará su informe como se muestra a
continuación:
Resumen médico (para ver todos los detalles, ejecute flutter doctor -v):
[ÿ] Flutter (Canal estable, v1.2.1, en Microsoft Windows [Versión 10.0.17134.706],
configuración regional en-US)
[ÿ] Cadena de herramientas de Android: desarrollo para dispositivos Android (Android SDK versión
28.0.3)
[ÿ] Android Studio (versión 3.2)
[ÿ] VS Code, edición de 64 bits (versión 1.29.1)
[!] Dispositivo conectado
! No hay dispositivos disponibles
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.
Paso 9: Instale el complemento Flutter and 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.
3
Machine Translated by Google
Aleteo
Instalación en macOS
Para instalar Flutter en MacOS, tendrás que seguir los siguientes pasos:
Paso 3: actualice la ruta del sistema para incluir el directorio flutter bin (en el archivo ~/.bashrc).
Paso 4: habilite la ruta actualizada en la sesión actual usando el siguiente comando y luego verifíquelo también.
fuente ~/.bashrc
fuente $HOME/.bash_profile echo
$RUTA
Flutter proporciona una herramienta, flutter doctor para verificar que se cumplan todos los requisitos del desarrollo de
flutter. Es similar a la contraparte de Windows.
Paso 8: Inicie un emulador de Android o conecte un dispositivo Android real al sistema para desarrollar una aplicación
de Android.
Paso 9: Abra el simulador de iOS o conecte un dispositivo iPhone real al sistema para desarrollar la aplicación iOS.
Paso 10: Instale el complemento Flutter and Dart para Android Studio. Proporciona la plantilla de inicio para crear una
nueva aplicación Flutter, la opción de ejecutar y depurar la aplicación Flutter en el propio estudio de Android, etc.
4
Machine Translated by Google
Aleteo
3. Flutter: creación de una aplicación
sencilla en Android Studio
En este capítulo, vamos a crear una aplicación Flutter simple para comprender los conceptos básicos de
la creación de una aplicación Flutter en Android Studio.
Paso 2: Crea un Proyecto Flutter. Para esto, haga clic en Archivo -> Nuevo -> Nuevo proyecto Flutter
5
Machine Translated by Google
Aleteo
Paso 3: seleccione la aplicación Flutter. Para ello, seleccione Aplicación Flutter y haga clic en Siguiente.
6
Machine Translated by Google
Aleteo
Android Studio crea una aplicación flutter completamente funcional con una funcionalidad mínima.
Verifiquemos la estructura de la aplicación y luego, cambiemos el código para hacer nuestra tarea.
7
Machine Translated by Google
Aleteo
• Android : código fuente generado automáticamente para crear una aplicación de Android
• ios : código fuente generado automáticamente para crear una aplicación ios
• lib - Carpeta principal que contiene código Dart escrito usando flutter framework
• test - Carpeta que contiene el código Dart para probar la aplicación flutter
8
Machine Translated by Google
Aleteo
Paso 7: Reemplace el código dart en el archivo lib/ main.dart con el siguiente código:
devolver MaterialApp(
title: 'Aplicación de demostración Hello World',
theme: ThemeData( PrimarySwatch: Colors.blue, ),
home: MyHomePage(title: 'Home page'), );
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title:
Text(this.title), ), body: Center( child:
Text( 'Hello World',
), );
}
}
• Línea 1: importa el paquete flutter, material. El material es un paquete flutter para crear una
interfaz de usuario de acuerdo con las pautas de diseño de materiales especificadas por
Android.
• Línea 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.
• Línea 5 - 17: el widget se usa para crear una interfaz de usuario en el marco flutter.
StatelessWidget es un widget que no mantiene ningún estado del widget. MyApp amplía
StatelessWidget y anula su método de compilación . El propósito de la construcción
9
Machine Translated by Google
Aleteo
o tema es el tema del widget. Aquí, establecemos el azul como el color general de la
aplicación utilizando la clase ThemeData y su propiedad, primarySwatch.
• Línea 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 centra su widget secundario. El texto es el widget final y más
interno para mostrar el texto y se muestra en el centro de la
pantalla.
10
Machine Translated by Google
Aleteo
11
Machine Translated by Google
Widgets
El concepto central del marco Flutter es En Flutter, todo es un 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.
Por ejemplo, la jerarquía de widgets de la aplicación hello world (creada en el capítulo anterior) se especifica
en el siguiente diagrama:
12
Machine Translated by Google
Aleteo
• MyApp es el widget creado por el usuario y se construye usando 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 es nuevamente un widget creado por el usuario, MyHomePage.
• body se usa para especificar su interfaz de usuario principal y appBar se usa para especificar su encabezado
interfaz de usuario.
• La interfaz de usuario del encabezado se crea con el widget nativo de flutter, la barra de aplicaciones y la interfaz de usuario del cuerpo se crean con
Widget central .
• El widget Center tiene una propiedad, Child, que hace referencia 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 funciones interactivas 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 StatelessWidget. Los widgets de Flutter son reactivos en nativo. Esto es similar a reactjs y
StatefulWidget se renderizará automáticamente cada vez que se cambie su estado interno. La nueva representación se
optimiza encontrando la diferencia entre la interfaz de usuario del widget antiguo y el nuevo y presentando solo los
cambios necesarios.
Capas
El concepto más importante del marco Flutter es que el marco se agrupa en múltiples categorías en términos de
complejidad y se organiza claramente en capas de complejidad decreciente. Una capa se crea utilizando su capa de
nivel inmediatamente siguiente. La capa 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.
13
Machine Translated by Google
Aleteo
• Las funciones interactivas se pueden incorporar cuando sea necesario usando GestureDetector
artilugio.
• El estado de un widget se puede mantener siempre que sea necesario usando StatefulWidget
artilugio.
• Flutter ofrece un diseño en capas para que cualquier capa se pueda programar según la complejidad
de la tarea.
14
Machine Translated by Google
Aleteo
5. Flutter – Introducción a la programación de dardos
vacío principal()
{
print("El lenguaje Dart es fácil de aprender");
}
Dart usa la palabra clave var para declarar la variable. La sintaxis de var se define a continuación,
Las palabras clave final y const se utilizan para declarar constantes. Se definen como sigue:
vacío principal ()
{ final a = 12;
constante pi = 3,14;
imprimir (a); imprimir
(pi);
}
• Strings: Representa una secuencia de caracteres. Los valores de cadena se especifican entre comillas
simples o dobles.
• Booleanos: Dart usa la palabra clave bool para representar valores booleanos: verdadero y falso.
• Listas y Mapas: Se utiliza para representar una colección de objetos. Una lista simple se puede definir
de la siguiente manera:
15
Machine Translated by Google
Aleteo
void main()
{ nombre dinámico = "Dart";
imprimir (nombre);
}
Los bucles se utilizan para repetir un bloque de código hasta que se cumpla una condición específica. Soportes para dardos
para, para..en , while y do..while bucles.
void main()
{ for( var i = 1 ; i <= 10; i++ ) { if(i%2==0)
{
imprimir (yo);
}
}
}
Funciones
Una función es un grupo de declaraciones que juntas realizan una tarea específica. echemos un vistazo a
una función simple en Dart como se muestra aquí:
vacío principal ()
{ añadir (3,4);
}
dieciséis
Machine Translated by Google
Aleteo
Una clase es un modelo para crear objetos. Una definición de clase incluye lo siguiente:
• Campos
• Getters y setters
• Constructores
• Funciones
clase Empleado {
Nombre de cadena;
//método captador
String get emp_name { nombre
de retorno;
}
//método setter
void set emp_name(String nombre) { this.name
= nombre;
}
//definicion de la funcion
resultado nulo()
{
imprimir (nombre);
}
} void main() { //
creación de objetos
Empleado emp = nuevo Empleado();
emp.nombre="empleado1";
emp.resultado(); //Llamada de función
}
17
Machine Translated by Google
Aleteo
6. Flutter – Introducción a los widgets
Como aprendimos en el capítulo anterior, los widgets lo son todo en el marco de trabajo de Flutter. Ya hemos
aprendido cómo crear nuevos widgets en capítulos anteriores.
En este capítulo, comprendamos el concepto real detrás de la creación de widgets y los diferentes tipos de
widgets disponibles en el marco Flutter .
Veamos el widget MyHomePage de la aplicación Hello World . El código para este propósito es el siguiente:
@anular
Compilación del widget (contexto BuildContext) {
andamio de vuelta(
barra de aplicaciones: barra de aplicaciones (
título: Texto(este.título),
),
cuerpo: Centro(
niño: Texto(
'Hola Mundo',
)),
);
}
}
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 construye.
En el código, hemos usado el título como uno de los argumentos del constructor y también usamos la clave
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
método de AppBar y Center para construir su interfaz de usuario.
18
Machine Translated by Google
Aleteo
En Flutter, los widgets se pueden agrupar en varias categorías según sus características, como se indica a continuación:
• Widgets de diseño
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 .
• Andamio
• Barra de aplicaciones
19
Machine Translated by Google
Aleteo
• Barra de pestañas
• TabBarView
Azulejo de lista
• Botón elevado
• Botón de icono
• Botón desplegable
• Barra de botones
• Campo de texto
• Casilla de verificación
• Radio
• Cambiar
• Control deslizante
• SimpleDialog •
AlertDialog
• Botón de Cupertino
• Selector de Cupertino
• CupertinoDatePicker •
CupertinoTimerPicker
• CupertinoTabScaffold •
CupertinoTabView •
CupertinoTextField
• Diálogo de Cupertino
• CupertinoDialogAction
• CupertinoFullscreenDialogTransition •
CupertinoPageScaffold
• CupertinoActivityIndicator •
CupertinoAlertDialog •
CupertinoPopupSurface
20
Machine Translated by Google
Aleteo
• CupertinoSlider
Widgets de diseño
En Flutter, se puede crear un widget al componer uno o más widgets. Para componer múltiples 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 usando el widget Center .
Revisaremos los widgets de diseño en detalle en la próxima Introducción a los widgets de diseño.
capítulo.
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 los cambios de estado durante la interacción. Por ejemplo, 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 utilizando la nueva información de estado.
Flutter proporciona una gran cantidad de widgets básicos para crear una interfaz de usuario simple y compleja
de manera independiente a la plataforma. Veamos algunos de los widgets básicos en este capítulo.
Texto
El widget de texto se utiliza para mostrar un trozo de cadena. 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:
El widget de texto tiene un constructor especial, Text.rich, que acepta el elemento secundario de tipo TextSpan
para especificar la cadena con un estilo diferente. El widget TextSpan es de naturaleza recursiva y acepta
TextSpan como sus elementos secundarios. El código de muestra para este propósito es el siguiente:
21
Machine Translated by Google
Aleteo
Las propiedades más importantes del widget de texto son las siguientes:
• textAlign, TextAlign: Alineación del texto como derecha, izquierda, justificar, etc., usando
clase TextAlign
• textDirection, TextDirection: dirección del flujo de texto, ya sea de izquierda a derecha o de derecha
a la izquierda
Imagen
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:
La opción más sencilla 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.
• Crear una carpeta, activos en la carpeta del proyecto y colocar las imágenes necesarias.
aleteo:
activos:
- activos/smiley.png
Imagen.activo('activos/sonrisa.png')
22
Machine Translated by Google
Aleteo
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title:
Text(this.title), ), body: Center( child:
Image.asset("assets/smiley.png")
), );
}
23
Machine Translated by Google
Aleteo
Las propiedades más importantes del widget Imagen son las siguientes:
Icono
El widget de icono se usa 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:
Icono(Iconos.email)
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title:
Text(this.title), ), body: Center( child:
Icon(Icons.email)
), );
}
}
24
Machine Translated by Google
Aleteo
25
Machine Translated by Google
Aleteo
7. Flutter – Introducción a los diseños
Dado que el concepto central de Flutter es que todo es un 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 construyen al componer otros widgets que normalmente usan widgets de diseño. Vamos a aprender
el concepto de diseño de Flutter en este capítulo.
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 dentro de él usando
diferentes opciones como relleno, decoración, etc.
Los widgets de un solo hijo son excelentes opciones para crear widgets de alta calidad que tengan una
funcionalidad única, como un botón, una etiqueta, etc.
@anular
Compilación del widget (contexto BuildContext) {
contenedor de retorno(
decoración: const BoxDecoration(
borde: borde (
arriba: BorderSide (ancho: 1.0, color: Color (0xFFFFFFFFFF)),
izquierda: BorderSide (ancho: 1.0, color: Color (0xFFFFFFFFFF)),
derecha: BorderSide (ancho: 1.0, color: Color (0xFFFF000000)),
inferior: BorderSide (ancho: 1.0, color: Color (0xFFFF000000)),
),
),
niño: contenedor (
relleno: const EdgeInsets.simétrico (horizontal: 20,0, vertical: 2,0),
decoración: const BoxDecoration(
borde: borde (
arriba: BorderSide (ancho: 1.0, color: Color (0xFFFFDFDFDF)),
26
Machine Translated by Google
Aleteo
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 hijo más importantes proporcionados por Flutter:
• Relleno: Se utiliza para organizar su widget hijo por el relleno dado. Aquí, la clase EdgeInsets puede
proporcionar relleno .
• Alinear: alinea su widget secundario 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 los desplazamientos en términos de distancia desde la parte superior izquierda.
Centrar(
niño: contenedor (
altura: 100.0,
ancho: 100.0,
color: Colores.amarillo,
niño: alinear (
alineación: Compensación fraccional (0.2, 0.6),
niño: contenedor (
altura: 40.0,
ancho: 40.0,
color: colores.rojo,
),
),
),
)
• FittedBox: escala el widget secundario y luego lo posiciona de acuerdo con el ajuste especificado.
• Relación de aspecto: intenta ajustar el tamaño del widget secundario a la relación de aspecto especificada
27
Machine Translated by Google
Aleteo
• Caja restringida
• Base
• FractinalySizedBox
• Altura intrínseca
• Ancho intrínseco
• AdhesivosCaja
• Caja de desbordamiento
• Caja de tamaño
• SizedOverflowBox
• Transformar
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 construir la página de inicio utilizando widgets de diseño básicos
como se especifica a continuación:
• Contenedor: Widget de contenedor genérico, hijo único, basado en cuadro con alineación, relleno, borde
y margen junto con ricas características de estilo.
• Centro: Widget de contenedor secundario simple y único, que centra su widget secundario.
@anular
@anular
contenedor de retorno(
decoración: BoxDecoración(
28
Machine Translated by Google
Aleteo
color: colores.blanco,
),
relleno: EdgeInsets.all(25),
Texto(
'Hola Mundo',
estilo: EstiloTexto(
color: colores.negro,
),
DirecciónTexto: DirecciónTexto.ltr,
),
));
Aquí,
• El widget contenedor es el widget raíz o de nivel superior. 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 Contenedor
widget y aquí, el color se usa para establecer el color del contenedor.
• El relleno del widget Contenedor se establece mediante la clase dgeInsets , que ofrece la opción de especificar
el valor de relleno.
• Centro es el widget secundario del widget Contenedor . 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, Contenedor.
29
Machine Translated by Google
Aleteo
El resultado final del código anterior es un ejemplo de diseño como se muestra a continuación:
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 de Fila permite la disposición de sus elementos secundarios en dirección horizontal, mientras
que el widget de Columna permite la disposición de sus elementos secundarios en dirección vertical. Al componer
Fila y Columna, se puede construir un widget con cualquier nivel de complejidad.
• Expandido: se usa para hacer que los hijos del widget Fila y Columna ocupen el
área máxima posible.
30
Machine Translated by Google
Aleteo
return MaterialApp(título:
'Flutter Demo', tema:
ThemeData(primarySwatch:
Colors.blue, ), home:
MyHomePage(título: 'Product layout
demo home page'), );
}
}
@anular
Creación de widgets (contexto BuildContext)
{ return Scaffold (
appBar:
AppBar( título:
Texto(este.título), ), cuerpo:
Centro( niño:
Texto(
'Hola Mundo', )),
);
}
}
31
Machine Translated by Google
Aleteo
• Aquí,
• 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 según el diseño especificado como se muestra
debajo:
nombre final de la
cadena; descripción final de la
cadena; precio internacional final;
imagen de cadena final;
Text(this.description), Text("Precio:
" + this.price.toString()), ], )))
]))); }
}
32
Machine Translated by Google
Aleteo
o Contenedor
o Ampliado
o Fila
o Columna
Tarjeta
o Texto
o Imagen
33
Machine Translated by Google
Aleteo
• 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:
activos:
- 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
34
Machine Translated by Google
Aleteo
Píxel.png
portatil.png
tableta.png
Pendrive.png
Disquete.png
• Finalmente, use el widget ProductBox en el widget MyHomePage como se especifica a continuación:
@anular
Compilación del widget (contexto de
BuildContext) { return Scaffold (appBar:
AppBar (título: Texto ("Lista de productos")), cuerpo: ListView
(shrinkWrap: true,
35
Machine Translated by Google
Aleteo
ProductBox( nombre:
"Pixel", descripción: "Pixel es el teléfono con más funciones", precio:
800, imagen: "pixel.png"), ProductBox( nombre: "Laptop", descripción:
"La computadora portátil es la herramienta de desarrollo más productiva
", precio: 2000, imagen: "laptop.png"),
ProductBox( name:
"Tablet", description: "Tablet es el dispositivo más útil para
reunión",
precio: 1500,
imagen: "tablet.png"),
ProductBox( nombre:
"Pendrive", descripción: "Pendrive es un medio de
almacenamiento útil", precio: 100, imagen: "pendrive.png"),
ProductBox(
nombre: "Unidad de
disquete", descripción: "La unidad de disquete es un medio de almacenamiento
de rescate útil", precio: 20, imagen: "floppy.png"),
], ));
}
}
• Aquí, hemos utilizado ProductBox como elementos secundarios del widget ListView .
return MaterialApp(título:
'Flutter Demo', tema:
ThemeData(primarySwatch:
Colors.blue,
36
Machine Translated by Google
Aleteo
),
home: MyHomePage(título: 'Página de inicio de demostración de diseño de producto'), );
}
}
@override
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title: Text("Product
Listing")), cuerpo: ListView(shrinkWrap: true, padding: const
EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0) , niños:
<Widget>[ ProductBox( nombre: "iPhone", descripción:
"iPhone es el teléfono con más estilo", precio: 1000, imagen: "iphone.png"),
ProductBox( nombre:
"Pixel", descripción: "Pixel es el teléfono con más funciones", precio:
800, imagen: "pixel.png"), ProductBox( nombre: "Laptop", descripción:
"La computadora portátil es la herramienta de desarrollo más productiva
", precio: 2000, imagen: "laptop.png"),
ProductBox( name:
"Tablet", description: "Tablet es el dispositivo más útil para
reunión",
precio: 1500,
imagen: "tablet.png"),
ProductBox( nombre:
"Pendrive", descripción: "Pendrive es un medio de
almacenamiento útil", precio: 100, imagen: "pendrive.png"),
ProductBox(
nombre: "Unidad de
disquete", descripción: "La unidad de disquete es un medio de almacenamiento
de rescate útil", precio: 20, imagen: "floppy.png"),
], ));
}
}
37
Machine Translated by Google
Aleteo
nombre final de la
cadena; descripción final de la
cadena; precio internacional final;
imagen de cadena final;
Peso de la fuente.negrita)),
Text(this.description),
Text("Precio: " + this.price.toString()), ], )))
])));
}
}
38
Machine Translated by Google
Aleteo
39
Machine Translated by Google
Aleteo
8. Flutter – Introducción a los gestos
Los gestos son principalmente una forma en que un usuario interactúa 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 hasta acciones más complejas que se usan en las aplicaciones de juegos.
• Tocar: tocar la superficie del dispositivo con la yema del dedo durante un período corto y luego
soltando la yema del dedo.
• Arrastrar: 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.
• Panorámica: tocar la superficie del dispositivo con la yema del dedo y moverlo en cualquier dirección
sin soltar la yema del dedo.
Flutter brinda 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.
Toque
o onTapDown
el onTapUp
o en el toque
el onTapCancelar
• Doble toque
o onDoubleTap
• Pulsación larga
o onLongPress
40
Machine Translated by Google
Aleteo
• Arrastre vertical
o onVerticalDragStart
o onVerticalDragUpdate
o onVerticalDragEnd
• Arrastre horizontal
el onHorizontalDragStart
la actualización onHorizontalDrag
el onHorizontalDragEnd
• Pan
o enPanStart
o onPanUpdate
o enPanEnd
Ahora, modifiquemos la aplicación hello world para incluir la función de detección de gestos y tratemos
de entender el concepto.
• Cambie el contenido del cuerpo del widget MyHomePage como se muestra a continuación:
cuerpo: Centro
(hijo: GestureDetector
(onTap: ()
{ _showDialog (contexto);
},
hijo: Texto(
'Hola Mundo',
)
)
),
• Observe que aquí hemos colocado el widget GestureDetector encima del texto
widget en la jerarquía de widgets, capturó el evento onTap y finalmente mostró una ventana de
diálogo.
• Implemente la función *_showDialog* para presentar un cuadro de diálogo cuando el usuario toque 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:
41
Machine Translated by Google
Aleteo
return AlertDialog(título:
nuevo texto("Mensaje"), contenido:
nuevo texto("Hola mundo"), acciones:
<Widget>[ new FlatButton( child: nuevo
texto("Cerrar"), onPressed: () { Navigator.
of(contexto).pop(); }, ), ], ); }, ); }
• La aplicación se recargará en el dispositivo utilizando la función Hot Reload . Ahora, simplemente haga
clic en el mensaje Hello World y se mostrará el siguiente cuadro de diálogo:
• Ahora, cierre el cuadro de diálogo haciendo clic en la opción de cerrar en el cuadro de diálogo.
42
Machine Translated by Google
Aleteo
devolver MaterialApp(
title: 'Aplicación de demostración Hello World',
theme: ThemeData( PrimarySwatch: Colors.blue, ),
home: MyHomePage(title: 'Home page'), );
}
}
Navegador.de(contexto).pop(); }, ), ], ); }, );
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title:
Text(this.title), ),
43
Machine Translated by Google
Aleteo
cuerpo: Centro
(hijo: GestureDetector (onTap:
() { _showDialog
(contexto); }, hijo: Texto (
);
}
}
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:
• PointerDown Event
• PointerMoveEvent
• PointerUpEvent
• Puntero Cancelar Evento
Flutter también proporciona un pequeño conjunto de widgets para realizar gestos específicos y avanzados.
Los widgets se enumeran a continuación:
• LongPressDraggable: Admite el gesto de arrastrar para mover un widget, cuando su elemento principal
widget también se puede arrastrar.
• AbsorbPointer: detiene el proceso de detección de gestos en sí mismo y, por lo tanto, cualquier widget
superpuesto tampoco puede participar en el proceso de detección de gestos y, por lo tanto, no se
genera ningún evento.
44
Machine Translated by Google
Aleteo
9. Flutter – Gestión de estado
Administrar el estado en una aplicación es uno de los procesos más importantes y necesarios en el ciclo de vida de una
aplicación.
• Una vez que el usuario haya iniciado sesión, la aplicación debe conservar los detalles del usuario que inició sesión en todos
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 haya retirado el carrito.
La administración de un estado se puede dividir en dos categorías según la duración del estado particular en una aplicación.
• Efímero: 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.
• estado de la aplicación: último para toda la aplicación, como detalles de usuario registrados, información del carrito,
etc., Flutter lo admite a través de scoped_model.
Vamos a crear un widget, RatingBox con mantenimiento de estado. El propósito del widget es mostrar la calificación actual
de un producto específico. El proceso paso a paso para crear un widget de RatingBox con mantenimiento de estado es el
siguiente:
45
Machine Translated by Google
Aleteo
return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max, children:
<Widget>[ Container( padding: EdgeInsets.all(0), child:
IconButton(
], );
}
46
Machine Translated by Google
Aleteo
Aquí, hemos usado tres estrellas, creadas con el widget IconButton y las hemos organizado usando el widget
Row en una sola fila. La idea es mostrar la calificación a través de la secuencia de estrellas rojas.
Por ejemplo, si la calificación es de dos estrellas, las dos primeras estrellas serán rojas y la última será blanca.
void _setRatingAsOne()
{ setState( () { _rating = 1; });
void _setRatingAsTwo() {
establecerEstado( ()
{ _puntuación =
2; });
}
void _setRatingAsThree()
{ setState( () { _rating = 3; });
• Aquí, cada método establece la calificación actual del widget a través de setState
• Conecte el gesto del usuario (tocar la estrella) al método de cambio de estado adecuado.
return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max, children:
<Widget>[ Container( padding: EdgeInsets.all(0), child:
IconButton(
47
Machine Translated by Google
Aleteo
onPressed: _setRatingAsTwo,
iconSize: _size, ), ),
Container( padding: EdgeInsets.all(0),
child: IconButton(
], );
}
Aquí, el evento onPressed llama a la función relevante para cambiar el estado y, posteriormente, cambiar la
interfaz de usuario. Por ejemplo, si un usuario hace clic en la tercera estrella, se llamará a _setRatingAsThree
y cambiará la _rating a 3. Como se cambia el estado, se volverá a llamar al método de compilación y la
interfaz de usuario se compilará y renderizará nuevamente.
void _setRatingAsOne()
{ setState( () { _rating = 1; });
void _setRatingAsTwo() {
establecerEstado( ()
{ _puntuación =
2; });
}
void _setRatingAsThree()
{ setState( () { _rating = 3; });
48
Machine Translated by Google
Aleteo
return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max, children:
<Widget>[ Container( padding: EdgeInsets.all(0), child:
IconButton(
], );
}
}
Vamos a crear una nueva aplicación y usar nuestro widget RatingBox recién creado para mostrar la
calificación del producto.
49
Machine Translated by Google
Aleteo
return MaterialApp(título:
'Flutter Demo', tema:
ThemeData(primarySwatch:
Colors.blue, ), home:
MyHomePage(título: 'Product state
demo home page'), );
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title:
Text(this.title), ), body: Center( child:
Texto(
'Hola Mundo', )),
);
}
}
• Aquí,
• Cree un widget de ProductBox para enumerar el producto junto con la calificación como se especifica a continuación:
nombre final de la
cadena; descripción final de la
cadena; precio internacional final;
imagen de cadena final;
50
Machine Translated by Google
Aleteo
MainAxisAlignment.spaceEvenly,
children:
<Widget>[ Text(this.name,
style: TextStyle(fontWeight:
Peso de la fuente.negrita)),
Text(this.description), Text("Precio:
" + this.price.toString()),
RatingBox(), ], )))
])));
}
}
@override
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title: Text("Product
Listing")), cuerpo: ListView(shrinkWrap: true, padding: const
EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0) , niños:
<Widget>[ ProductBox( nombre: "iPhone", descripción: "iPhone es
el teléfono con más estilo", precio: 1000, imagen: "iphone.png"), ProductBox( nombre:
"Pixel", descripción: " Pixel es el teléfono con más funciones de la historia", precio:
800, imagen: "pixel.png"), ProductBox (nombre: "Laptop", descripción: "La
computadora portátil es la herramienta de desarrollo más productiva",
51
Machine Translated by Google
Aleteo
precio: 2000,
imagen: "laptop.png"),
ProductBox( name:
"Tablet", description: "Tablet es el dispositivo más útil para
reunión",
precio: 1500,
imagen: "tablet.png"),
ProductBox( nombre:
"Pendrive", descripción: "Pendrive es un medio de
almacenamiento útil", precio: 100, imagen: "pendrive.png"),
CajaProducto(
nombre: "Unidad de disquete",
descripción: "La unidad de disquete es un almacenamiento de rescate útil
medio",
precio: 20,
imagen: "floppy.png"),
], ));
}
}
return MaterialApp(título:
'Flutter Demo', tema:
ThemeData(primarySwatch:
Colors.blue, ), home:
MyHomePage(título: 'Product layout
demo home page'), );
}
}
@anular
Widget build (contexto BuildContext) { return
Scaffold (appBar: AppBar (título: Texto
("Lista de productos")), cuerpo: ListView (
52
Machine Translated by Google
Aleteo
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( nombre:
"Pixel", descripción: "Pixel es el teléfono con más funciones", precio:
800, imagen: "pixel.png"), ProductBox( nombre: "Laptop", descripción:
"La computadora portátil es la herramienta de desarrollo más productiva
", precio: 2000, imagen: "laptop.png"),
ProductBox( name:
"Tablet", description: "Tablet es el dispositivo más útil para
reunión",
precio: 1500,
imagen: "tablet.png"),
ProductBox( nombre:
"Pendrive", descripción: "iPhone es el teléfono con más estilo",
precio: 100, imagen: "pendrive.png"), ProductBox(
ProductBox( nombre:
"iPhone", descripción: "iPhone es el teléfono con más estilo",
precio: 1000, imagen: "iphone.png"),
ProductBox( nombre:
"iPhone", descripción: "iPhone es el teléfono con más estilo",
precio: 1000, imagen: "iphone.png"),
], ));
}
}
53
Machine Translated by Google
Aleteo
int _calificación = 0;
void _setRatingAsOne()
{ setState( () { _rating = 1; });
void _setRatingAsTwo() {
establecerEstado( ()
{ _puntuación =
2; });
}
void _setRatingAsThree()
{ setState( () { _rating = 3; });
return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max, children:
<Widget>[ Container( padding: EdgeInsets.all(0), child:
IconButton(
54
Machine Translated by Google
Aleteo
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size, ), ),
], );
}
}
nombre final de la
cadena; descripción final de la
cadena; precio internacional final;
imagen de cadena final;
MainAxisAlignment.spaceEvenly,
children:
])));
}
}
55
Machine Translated by Google
Aleteo
56
Machine Translated by Google
Aleteo
Al hacer clic en la estrella de calificación, se actualizará la calificación del producto. Por ejemplo, establecer 2 estrellas
calificación para iPhone mostrará la calificación de la siguiente manera:
scoped_model proporciona tres clases principales para permitir una gestión de estado robusta en una aplicación que se analizan
en detalle aquí:
Modelo
El modelo encapsula el estado de una aplicación. Podemos usar tantos modelos (heredando la clase Model) como sea necesario
para mantener el estado de la aplicación. Tiene un solo método, notificar a los oyentes, que debe llamarse cada vez que cambia el
estado del modelo. notificarListeners hará las cosas necesarias para actualizar la interfaz de usuario.
57
Machine Translated by Google
Aleteo
Modelo de alcance
ScopedModel es un widget, que contiene el modelo dado y luego lo pasa a todos los widgets
descendientes si se solicita. Si se necesita más de un modelo, debemos anidar el ScopedModel.
• Modelo único
• Múltiples modelos
ScopedModel<Producto>( modelo:
item1, child:
ScopedModel<Producto>( modelo:
item2, child: AnyWidget(), ),
)
ScopedModel.of<Producto>(contexto).updateRating(2);
58
Machine Translated by Google
Aleteo
AlcanceModeloDescendiente
ScopedModelDescendant es un widget, que obtiene el modelo del widget de nivel superior, ScopedModel y
construye su interfaz de usuario cada vez que cambia el modelo.
ScopedModelDescendant tiene dos propiedades: constructor e hijo. child es la parte de la interfaz de usuario
que no cambia y se pasará al constructor. builder acepta una función con tres argumentos:
devuelve ScopedModelDescendant<ProductModel>(
constructor: (contexto, niño, carrito) => { ... IU real ... }, niño: PartOfTheUI(), );
aleteo:
activos:
- assets/appimages/floppy.png - assets/
appimages/iphone.png - assets/
appimages/laptop.png - assets/
appimages/pendrive.png - assets/
appimages/pixel.png - assets/appimages/
tablet.png
dependencias:
scoped_model: ^1.0.1
• Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo
configurará correctamente para la aplicación.
59
Machine Translated by Google
Aleteo
return MaterialApp(título:
'Flutter Demo', tema:
ThemeData(primarySwatch:
Colors.blue, ), home:
MyHomePage(título: 'Product state
demo home page'), );
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title:
Text(this.title), ), body: Center( child:
Text( 'Hello World', )),
);
}
}
import 'paquete:scoped_model/scoped_model.dart';
• Vamos a crear una clase Product, Product.dart para organizar la información del producto.
import 'paquete:scoped_model/scoped_model.dart';
60
Machine Translated by Google
Aleteo
Aquí, hemos usado notificar a los oyentes para cambiar la interfaz de usuario cada vez que se cambia la calificación.
items.add(Product( "Pixel",
"Pixel es el teléfono
con más funciones hasta ahora", 800, "pixel.png", 0));
items.add(Product( "Tablet",
"Tablet es el
dispositivo más útil para reuniones", 1500, "tablet.png", 0));
items.add(Producto(
61
Machine Translated by Google
Aleteo
"Unidad de disquete",
"La unidad de disquete es un medio de almacenamiento de rescate
útil", 20, "floppy.png", 0));
importar 'Producto.dardo';
return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, children: <Widget>[ Container( padding:
EdgeInsets.all(0), child: IconButton( icon: (item.rating >= 1 ?
Icono( Iconos.estrella, tamaño: _tamaño,
)
:
Icon( Icons.star_border, size:
_size, )), color:
Colors.red[500], onPressed:
() => this.item.updateRating(1),
iconSize: _size, ), ), Container( padding: EdgeInsets.all(0),
child: IconButton( icon: (item.rating >= 2 ? Icon( Icons.star,
size: _size,
)
: Icono
(Iconos.star_border,
tamaño: _tamaño,
62
Machine Translated by Google
Aleteo
)),
color: Colors.red[500],
onPressed: () => this.item.updateRating(2), iconSize:
_size, ), ), Container( padding: EdgeInsets.all(0), child:
IconButton( icono: (artículo.valoración >= 3 ?
Icono( Iconos.estrella, tamaño: _tamaño,
)
:
Icon( Icons.star_border,
size: _size, )), color:
Colors.red[500], onPressed:
() => this.item.updateRating(3),
iconSize: _size, ), ), ], );
}
}
• Modifiquemos nuestro widget ProductBox para que funcione con Product, ScopedModel y
Clase ScopedModelDescendant.
63
Machine Translated by Google
Aleteo
mainAxisAlignment:
MainAxisAlignment.spaceEvenly, niños: <Widget>[
Text(this.item.name,
style:
TextStyle(fontWeight:
Peso de la fuente.negrita)),
Texto(este.artículo.descripción),
Texto("Precio: " +
este.artículo.precio.toString()),
ScopedModelDescendant<Producto>(
constructor: (contexto, hijo, artículo) {
devuelve RatingBox (elemento:
elemento); }) ], ))))
]),
));
}
}
@override
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title:
Text("Navegación del producto")), cuerpo: ListView.builder(
itemCount: items.length,
itemBuilder: (contexto, índice) { return
ProductBox(item: items[index]); }, ));
}
}
Aquí, hemos usado ListView.builder para construir dinámicamente nuestra lista de productos.
Producto.dardo
import 'paquete:scoped_model/scoped_model.dart';
64
Machine Translated by Google
Aleteo
vacío cn
"La computadora portátil es la herramienta de desarrollo más
productiva", 2000, "laptop.png", 0));
items.add(Producto( "Unidad
de disquete", "Unidad
de disquete es un medio de almacenamiento de rescate útil", 20,
"disquete.png", 0));
sesenta y cinco
Machine Translated by Google
Aleteo
@anular
Compilación del widget (contexto BuildContext) {
return MaterialApp(título:
'Flutter Demo', tema:
ThemeData(primarySwatch:
Colors.blue, ), home:
MyHomePage(título: 'Product state
demo home page'), );
}
}
@override
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title:
Text("Navegación del producto")), cuerpo: ListView.builder(
itemCount: items.length,
itemBuilder: (contexto, índice) { return
ProductBox(item: items[index]); }, ));
}
}
return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max, children:
<Widget>[ Container( padding: EdgeInsets.all(0), child:
IconButton( icon: (item.rating >= 1 ?
Icono( Iconos.estrella, tamaño: _tamaño,
)
: Icono(
66
Machine Translated by Google
Aleteo
Icons.star_border,
size: _size, )), color:
Colors.red[500],
onPressed: () =>
this.item.updateRating(1), iconSize: _size, ), ),
Container( padding: EdgeInsets.all (0), child:
IconButton( icon: (item.rating >= 2 ? Icon( Icons.star, size:
_size,
)
:
Icon( Icons.star_border,
size: _size, )), color:
Colors.red[500],
onPressed: () =>
this.item.updateRating(2), iconSize: _size, ), ),
Container( padding: EdgeInsets.all(0), child:
IconButton( icon: (item.rating >= 3 ? Icon( Icons.star, size:
_size,
)
:
Icon( Icons.star_border,
size: _size, )), color:
Colors.red[500],
onPressed: () =>
this.item.updateRating(3), iconSize: _size, ), ), ], );
}
}
67
Machine Translated by Google
Aleteo
altura: 140,
hijo: Tarjeta
(hijo: Fila (
mainAxisAlignment: MainAxisAlignment.spaceEvenly, children:
<Widget>[ Image.asset("assets/appimages/" + this.item.image),
Expanded( child: Container( padding: EdgeInsets.all(5), child:
ScopedModel<Product >( modelo: this.item, child:
Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name, style:
TextStyle(fontWeight:
Peso de la fuente.negrita)),
Texto(este.artículo.descripción),
Texto("Precio: " +
este.artículo.precio.toString()),
ScopedModelDescendant<Producto>(
constructor: (contexto, hijo, elemento) {
devuelve RatingBox (elemento:
elemento); }) ], ))))
]),
));
}
}
Finalmente, compile y ejecute la aplicación para ver su resultado. Funcionará de manera similar al ejemplo
anterior, excepto que la aplicación usa el concepto 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 llama 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 usa para representar su interfaz de usuario al reemplazar toda la pantalla con una
animación específica de la plataforma.
Aquí, el constructor aceptará una función para construir su contenido proporcionando el contexto actual de la
aplicación.
Navegación.push
68
Machine Translated by Google
Aleteo
Navigation.push se usa para navegar a una nueva pantalla usando el widget MaterialPageRoute.
Navigator.push(contexto,
Navegación.pop
Navigation.pop se utiliza para navegar a la pantalla anterior.
Navigator.push(contexto);
Vamos a crear una nueva aplicación para comprender mejor el concepto de navegación.
aleteo:
activos:
- assets/appimages/floppy.png - assets/
appimages/iphone.png - assets/
appimages/laptop.png - assets/
appimages/pendrive.png - assets/
appimages/pixel.png - assets/appimages/
tablet.png
return MaterialApp(título:
'Flutter Demo', tema:
ThemeData(primarySwatch:
Colors.blue, ), home:
MyHomePage(título: 'Product state
demo home page'), );
}
}
69
Machine Translated by Google
Aleteo
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title:
Text(this.title), ), body: Center( child:
Text( 'Hello World', )),
);
}
}
• Vamos a crear una clase Producto para organizar la información del producto.
clase Producto
{ cadena final nombre;
descripción final de la cadena;
precio internacional final; imagen
de cadena final;
items.add(Product( "Pixel",
"Pixel es el
teléfono con más funciones hasta ahora", 800,
"pixel.png"));
70
Machine Translated by Google
Aleteo
100,
"pendrive.png"));
items.add(Producto( "Unidad
de disquete", "La
unidad de disquete es un medio de almacenamiento de rescate
útil", 20, "disquete.png"));
importar 'Producto.dardo';
void _setRatingAsOne()
{ setState(() { _rating = 1; });
void _setRatingAsTwo()
{ setState(() { _rating = 2; });
void _setRatingAsThree() {
setState(()
{ _puntuación
= 3; });
}
return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max, children:
<Widget>[ Container( padding: EdgeInsets.all(0), child:
IconButton(
71
Machine Translated by Google
Aleteo
}
}
72
Machine Translated by Google
Aleteo
• Modifiquemos nuestro widget ProductBox para que funcione con nuestra nueva clase Product.
niños: <Widget>[
Text(this.item.name,
style: TextStyle(fontWeight:
Peso de la fuente.negrita)),
Text(this.item.description),
Text("Precio: " + this.item.price.toString()), RatingBox(), ], )))
]),
));
}
}
• Reescribamos nuestro widget MyHomePage para que funcione con el modelo de Producto y para listar todos
los productos usando ListView.
@override
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title:
Text("Navegación del producto")), cuerpo: ListView.builder(
itemCount: items.length,
itemBuilder: (contexto, índice) {
73
Machine Translated by Google
Aleteo
), ); }, ); }, ));
}
}
Aquí, hemos utilizado MaterialPageRoute para navegar a la página de detalles del producto.
@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/" +
esta.imagen.del.elemento),
Expandido( hijo:
Contenedor( relleno: EdgeInsets.all(5),
hijo: Columna( mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
niños: <Widget>[
Text(this.item.name, style:
TextStyle(fontWeight:
Peso de la fuente.negrita)),
Texto(este.artículo.descripción),
Texto("Precio: " +
este.artículo.precio.toString()),
Cuadro de clasificación(),
74
Machine Translated by Google
Aleteo
], )))
]),
),
), );
}
}
clase Producto
{ cadena final nombre;
descripción final de la cadena;
precio internacional final; imagen
de cadena final;
items.add(Producto( "Pixel",
"Pixel es el teléfono con más funciones de la historia", 800,
"píxel.png"));
2000, "portátil.png"));
75
Machine Translated by Google
Aleteo
return MaterialApp(título:
'Flutter Demo', theme:
ThemeData(primarySwatch:
Colors.blue, ), home:
MyHomePage(title: 'Product
Navigation demo home page'), );
}
}
@override
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title:
Text("Navegación del producto")), cuerpo: ListView.builder(
itemCount: items.length,
itemBuilder: (contexto, índice) { return
GestureDetector( child:
ProductBox(item: items[index]), onTap: ()
{ Navigator.push( context, MaterialPageRoute(
), ); }, ); }, ));
}
}
@anular
Widget compilación (contexto BuildContext)
{ return Scaffold (appBar: AppBar (
76
Machine Translated by Google
Aleteo
MainAxisAlignment.spaceEvenly,
niños: <Widget>[
Text(this.item.name, style:
TextStyle(fontWeight:
Peso de la fuente.negrita)),
Texto(este.artículo.descripción),
Texto("Precio: " +
este.artículo.precio.toString()),
Cuadro de
clasificación(), ], )))
]),
),
), );
}
}
void _setRatingAsOne()
{ setState(() { _rating = 1; });
void _setRatingAsTwo()
{ setState(() { _rating = 2; });
void _setRatingAsThree()
{ setState(() {
77
Machine Translated by Google
Aleteo
_puntuación =
3; });
}
return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, children: <Widget>[ Container( padding:
EdgeInsets.all(0), child: IconButton(
78
Machine Translated by Google
Aleteo
:
Icon( Icons.star_border,
size: _size, )), color:
Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size, ), ), ], );
}
}
Text(this.item.name,
style: TextStyle(fontWeight:
Peso de la fuente.negrita)),
Text(this.item.description),
Text("Precio: " + this.item.price.toString()), RatingBox(), ], )))
]),
));
}
}
79
Machine Translated by Google
Aleteo
Ejecute la aplicación y haga clic en cualquiera de los elementos del producto. Mostrará la página de
detalles relevante. Podemos pasar 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 de productos de la aplicación se muestran a continuación:
80
Machine Translated by Google
Aleteo
81
Machine Translated by Google
Aleteo
10. Aleteo – Animación
Introducción
La animación es un proceso de mostrar una serie de imágenes/imagen 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
inicial y pasa por una serie de valores intermedios y finalmente termina en los valores finales . 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 pueden configurar.
Comprenda que la animación funciona tal 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.
• En Flutter, el sistema de animación no hace ninguna animación real. En su lugar, proporciona solo
los valores necesarios en cada cuadro para representar las imágenes.
Animación
Genera valores interpolados entre dos números durante un tiempo determinado. Las clases de Animación
más comunes son:
82
Machine Translated by Google
Aleteo
• AnimationController: objeto de animación especial para controlar la propia animación. Genera nuevos valores cada
vez que la aplicación está lista para un nuevo marco. Admite animación lineal y el valor comienza de 0.0 a 1.0.
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.
CurvaAnimación
Similar a AnimationController pero admite animación no lineal. CurvedAnimation se puede usar junto con el objeto de
animación de la siguiente manera:
Interpolación<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 de animación utilizando el método de animación y pasando el objeto de animación real.
Tween también se puede usar junto con CurvedAnimation como se muestra a continuación:
Aquí, el controlador es el controlador de animación real. curve proporciona el tipo de no linealidad y customTween proporciona
un rango personalizado de 0 a 255.
• Agregar oyente basado en animación, addListener para cambiar el estado del widget
83
Machine Translated by Google
Aleteo
valor. });
});
• Se pueden usar widgets incorporados, AnimatedWidget y AnimatedBuilder para omitir este proceso. Ambos
widgets aceptan el objeto Animación y obtienen los valores actuales necesarios para la animación.
• Obtenga los valores de la animación durante el proceso de creación del widget y luego aplíquelo para el
ancho, la altura o cualquier propiedad relevante en lugar del valor original.
Aplicación de trabajo
Escribamos una aplicación simple basada en animación para comprender el concepto de animación en el marco
Flutter.
aleteo:
activos:
- activos/imágenes de la aplicación/disquete.png
- activos/imágenes de la aplicación/iphone.png
- activos/imágenes de la aplicación/portátil.png
- activos/imágenes de la aplicación/pendrive.png
- activos/imágenes de la aplicación/pixel.png
- activos/imágenes de la aplicación/tableta.png
84
Machine Translated by Google
Aleteo
• Cree el widget _MyAppState e implemente initState y elimínelo además del método de compilación
predeterminado.
Animación<doble> animación;
Controlador AnimationController;
@override
void initState() {
super.initState();
controlador = AnimationController (duración: const Duración (segundos: 10), vsync: esto);
);
}
@override
void dispose()
{ controlador.dispose();
super.dispose();
}
}
Aquí,
85
Machine Translated by Google
Aleteo
: super(clave: clave);
nombre final de la
cadena; descripción final de la
cadena; precio internacional final;
imagen de cadena final;
Peso de la fuente.negrita)),
Text(this.description),
Text("Precio: " + this.price.toString()), ], )))
])));
}
}
• Cree un nuevo widget, MyAnimatedWidget para hacer una animación de fundido simple usando opacidad.
);
}
• Aquí, hemos usado AniatedBuilder 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 animación.
86
Machine Translated by Google
Aleteo
value, animation.value para establecer la opacidad del widget secundario. En efecto, el widget
animará al widget secundario utilizando el concepto de opacidad.
• Finalmente, cree el widget MyHomePage y use el objeto de animación para animar cualquier
parte de su contenido.
@override
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title: Text("Product
Listing")), cuerpo: ListView(shrinkWrap: true, padding: const
EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0) , niños:
<Widget>[ FadeTransition(child: ProductBox( nombre:
"iPhone", descripción: "iPhone es el teléfono con más estilo", precio: 1000,
imagen: "iphone.png"), opacidad: animación), MyAnimatedWidget( niño:
ProductBox (nombre: "Pixel", descripción: "Pixel es el teléfono con más
funciones", precio: 800, imagen: "pixel.png"),
animación: animación),
ProductBox( nombre:
"Laptop", descripción:
"Laptop es la herramienta de desarrollo más productiva", precio: 2000,
imagen: "laptop.png"), ProductBox( nombre: "Tablet", descripción: "Tablet
is el dispositivo más útil para
reunión",
precio: 1500,
imagen: "tablet.png"),
ProductBox (nombre: "Pendrive",
descripción: "Pendrive es
un medio de almacenamiento útil", precio: 100, imagen:
"pendrive.png"), ProductBox (nombre: "Floppy Drive",
descripción: "La unidad de disquete es un almacenamiento de
rescate útil
medio",
precio: 20,
imagen: "floppy.png"),
],
87
Machine Translated by Google
Aleteo
));
}
}
Aquí, hemos usado 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.
Animación<doble> animación;
Controlador AnimationController;
@override
void initState() {
super.initState();
controlador = AnimationController (duración: const Duración (segundos: 10), vsync:
esto); animación = Tween<doble>(inicio: 0.0, fin: 1.0).animate(controlador);
controlador.adelante();
);
}
@override
void dispose()
{ controlador.dispose();
super.dispose();
}
}
88
Machine Translated by Google
Aleteo
@override
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title: Text("Product
Listing")), cuerpo: ListView(shrinkWrap: true, padding: const
EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0) , niños:
<Widget>[ FadeTransition(child: ProductBox( nombre:
"iPhone", descripción: "iPhone es el teléfono con más estilo", precio:
1000, imagen: "iphone.png"), opacidad: animación), MyAnimatedWidget( niño:
ProductBox (nombre: "Pixel", descripción: "Pixel es el teléfono con más
funciones", precio: 800, imagen: "pixel.png"),
animación: animación),
ProductBox( nombre:
"Laptop", descripción:
"Laptop es la herramienta de desarrollo más productiva", precio: 2000,
imagen: "laptop.png"), ProductBox( nombre: "Tablet", descripción: "Tablet
is el dispositivo más útil para
reunión",
precio: 1500,
imagen: "tablet.png"),
ProductBox( nombre:
"Pendrive", descripción: "Pendrive es un medio de
almacenamiento útil", precio: 100, imagen: "pendrive.png"),
ProductBox(
], ));
}
}
89
Machine Translated by Google
Aleteo
nombre final de la
cadena; descripción final de la
cadena; precio internacional final;
imagen de cadena final;
Peso de la fuente.negrita)),
Text(this.description),
Text("Precio: " + this.price.toString()), ], )))
])));
}
}
);
}
90
Machine Translated by Google
Aleteo
• Compile y ejecute la aplicación para ver los resultados. La versión inicial y final de
la aplicación es la siguiente:
91
Machine Translated by Google
Aleteo
92
Machine Translated by Google
Aleteo
11. Flutter: escritura de código específico de Android
Flutter proporciona un marco general para acceder a funciones específicas de la plataforma. Esto permite que el
desarrollador amplíe 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 la cámara, el nivel de la batería, el
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 de Flutter, el Cliente y el código de la plataforma y el Host se unen a un Canal de Mensajes común. El cliente
envía un mensaje al anfitrión a través del canal de mensajes. El host escucha en el canal de mensajes, recibe el mensaje
y realiza 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 mensajes 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 la
deserialización funcionan de forma transparente entre el cliente y el
anfitrión.
Escribamos una aplicación simple para abrir un navegador usando el SDK de Android y comprendamos cómo invocar el
SDK desde la aplicación flutter.
93
Machine Translated by Google
Aleteo
);
}
}
@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.
}
}
94
Machine Translated by Google
Aleteo
Aquí, hemos usado platform.invokeMethod para invocar openBrowser (explicado en los próximos pasos).
openBrowser tiene un argumento, url para abrir una url específica.
onPressed: _openBrowser,
importar android.app.Actividad;
importar android.content.Intent; importar
android.net.Uri; importar
android.os.Bundle;
private void openBrowser (MethodCall call, Result result, String url) { Actividad actividad =
esto; if (actividad == nulo) { result.error("ACTIVITY_NOT_AVAILABLE", "No se puede
abrir el navegador
actividad.startActivity(intención);
resultado.éxito((Objeto) verdadero);
}
• Escriba un código específico de Android para configurar el manejo de mensajes en el método onCreate.
if (llamada.método.equals("openBrowser")) {
95
Machine Translated by Google
Aleteo
}
});
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 a openBrowser solo cuando la llamada al método es openBrowser. De lo
contrario, devuelve el método no implementado.
dardo principal
MainActivity.java
paquete com.tutorialspoint.flutterapp.flutter_browser_app;
importar android.app.Actividad;
importar android.content.Intent; importar
android.net.Uri; importar
android.os.Bundle;
@Override
protected void onCreate(Paquete de estado de instancia guardado) {
super.onCreate(estadoDeInstanciaGuardado);
GeneratedPluginRegistrant.registerWith(this);
if (call.method.equals("openBrowser"))
{ openBrowser(call, result, url); } else
{ resultado.noImplementado();
96
Machine Translated by Google
Aleteo
});
}
actividad.startActivity(intención);
resultado.éxito((Objeto) verdadero);
}
}
dardo principal
}
}
97
Machine Translated by Google
Aleteo
}
}
@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 Navegador - Página de inicio es como se muestra en la captura de pantalla aquí:
98
Machine Translated by Google
Aleteo
99
Machine Translated by Google
Aleteo
12. Flutter: escribir código específico de iOS
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.
• Vamos a crear una nueva aplicación en Android Studio (macOS), flutter_browser_ios_app
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementación AppDelegate
- (BOOL)aplicación:(UIApplication *)aplicación
FinalizóLanzamientoConOpciones:(NSDictionary *)launchOptions {
//
[GeneratedPluginRegistrant registerWithRegistry:self];
// Punto de anulación para la personalización después del lanzamiento de la aplicación.
return [súper aplicación: la aplicación finalizó el
lanzamiento con opciones: opciones de lanzamiento];
}
@final
• Hemos agregado un método, openBrowser para abrir el navegador con la URL especificada. Eso
acepta argumento único, url.
[aplicación openURL:url];
}
100
Machine Translated by Google
Aleteo
FlutterViewController* controlador =
(FlutterViewController*)self.window.rootViewController;
métodoChannelWithName:@"flutterapp.tutorialspoint.com/browser"
mensajerobinario:controlador];
}
}];
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementación AppDelegate
- (BOOL)aplicación:(UIApplication *)aplicación
FinalizóLanzamientoConOpciones:(NSDictionary *)launchOptions {
métodoChannelWithName:@"flutterapp.tutorialspoint.com/browser"
mensajerobinario:controlador];
101
Machine Translated by Google
Aleteo
}
}];
[aplicación openURL:url];
}
@final
• 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.
102
Machine Translated by Google
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 compartibles. 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 principal a la aplicación.
exportar src/mi_código_privado.dart
• lib/* : cualquier número de archivos de código Dart organizados en cualquier estructura de carpetas personalizada.
Se puede acceder al código como,
Todos los archivos de código de Dart en el Paquete son simplemente clases de Dart y no tienen ningún requisito especial
para incluir un código de Dart en un Paquete.
Tipos de Paquetes
Dado que los paquetes Dart son básicamente una pequeña colección de funcionalidades similares, se pueden categorizar
según 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 de utilidad básicas como sustantivos (enumera los
sustantivos en inglés), sílabas (especifica el número de sílabas en una palabra.
Paquete de aleteo
Código Dart genérico, que depende del marco Flutter y solo se puede usar en un entorno móvil. Por ejemplo, fluro es un
enrutador personalizado para flutter. Depende del aleteo
marco de referencia.
103
Machine Translated by Google
Aleteo
Complemento de aleteo
Código Dart genérico, que depende del marco Flutter, así como del código de la plataforma subyacente (Android SDK o
iOS SDK). Por ejemplo, la cámara es un complemento para interactuar con la cámara del dispositivo. Depende del marco
Flutter, así como del marco subyacente para obtener acceso a la cámara.
dependencias:
palabras_en_inglés: ^3.1.5
• Durante el desarrollo en Android Studio, Android Studio detecta cualquier cambio en pubspec.yaml y muestra una
alerta de paquete de Android Studio para el desarrollador, como se muestra a continuación:
• Los paquetes 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 'paquete:english_words/english_words.dart';
sustantivos.tomar(50).forEach(imprimir);
• Aquí, hemos utilizado la función de sustantivos para obtener e imprimir las 50 palabras principales.
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 aprendimos 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. El
104
Machine Translated by Google
Aleteo
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.
• Haga clic en Archivo -> Nuevo proyecto Flutter y seleccione la opción Complemento Flutter.
• Puede ver una ventana de selección del complemento Flutter como se muestra aquí:
105
Machine Translated by Google
Aleteo
• Ingrese el nombre del complemento y otros detalles en la ventana como se muestra aquí:
106
Machine Translated by Google
Aleteo
}
}
importar android.app.Actividad;
importar android.content.Intent; importar
android.net.Uri; importar android.os.Bundle;
• Aquí, tenemos que importar la biblioteca requerida para abrir un navegador desde Android.
• Aquí, Registrar se usa para obtener información de contexto del código de invocación.
@Override
public void onMethodCall (llamada a MethodCall, resultado de resultado) {
107
Machine Translated by Google
Aleteo
if (call.method.equals("getPlatformVersion"))
{ result.success("Android " + android.os.Build.VERSION.RELEASE); } else if
(call.method.equals("openBrowser")) {
openBrowser(llamada, resultado, url); }
else { resultado.noImplementado();
}
}
actividad.startActivity(intención);
resultado.éxito((Objeto) verdadero);
}
mi_navegador.dart
clase Mi Navegador {
static const MethodChannel _channel = const
MethodChannel('my_browser');
108
Machine Translated by Google
Aleteo
}
}
MiBrowserPlugin.java
paquete com.tutorialspoint.flutterplugins.my_browser;
importar android.app.Actividad;
importar android.content.Intent; importar
android.net.Uri; importar
android.os.Bundle;
@Override
public void onMethodCall (llamada a MethodCall, resultado de resultado) {
Cadena url = llamada.argumento("url");
if (call.method.equals("getPlatformVersion"))
{ result.success("Android " + android.os.Build.VERSION.RELEASE); } else if
(call.method.equals("openBrowser")) {
openBrowser(llamada, resultado, url); }
else { resultado.noImplementado();
}
}
109
Machine Translated by Google
Aleteo
actividad.startActivity(intención);
resultado.éxito((Objeto) verdadero);
}
}
• Cree un nuevo proyecto, my_browser_plugin_test para probar nuestro complemento recién creado.
dependencias:
aleteo:
SDK: aleteo
mi_navegador:
ruta: ../mi_navegador
• Android Studio alertará que pubspec.yaml se actualizó 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.
import 'paquete:mi_navegador/mi_navegador.dart';
110
Machine Translated by Google
Aleteo
}
}
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title:
Text(this.title), ), body: Center( child:
RaisedButton( child: Text('Open
Browser'), onPressed: () = >
MiNavegador().openBrowser("https://
flutter.dev"), ), ), );
}
}
111
Machine Translated by Google
Aleteo
• Ejecute la aplicación y haga clic en el botón Abrir navegador y vea 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:
112
Machine Translated by Google
Aleteo
• Puede ver una aplicación de navegador: la pantalla del navegador como se muestra en la captura de pantalla que se muestra
debajo:
113
Machine Translated by Google
Aleteo
14. Flutter: acceso a la API REST
Flutter proporciona un paquete http para consumir recursos HTTP. http es una biblioteca basada en el futuro y
utiliza funciones de espera y asíncronas. Proporciona muchos métodos de alto nivel y simplifica el desarrollo de
aplicaciones móviles basadas en REST.
Conceptos básicos
El paquete http proporciona una clase de alto nivel y http para realizar solicitudes web.
• La clase http proporciona funcionalidad para realizar todo tipo de solicitudes HTTP.
• Los métodos http aceptan una URL e información adicional a través de Dart Map (datos de publicación,
encabezados adicionales, etc.). Solicita al servidor y recopila la respuesta en un patrón asíncrono/en
espera. Por ejemplo, el siguiente código lee los datos de la URL especificada y los imprime en la
consola.
imprimir(esperar http.read('https://flutter.dev/'));
• leer: solicita la URL especificada a través del método GET y devuelve la respuesta como Future<String>
• get: solicite la URL especificada a través del método GET y devuelva la respuesta como Future<Response>.
Respuesta es una clase que contiene la información de respuesta.
• post: solicite la URL especificada a través del método POST publicando los datos proporcionados y
devuelva la respuesta como Future<Response>
• put: solicita la URL especificada a través del método PUT y devuelve la respuesta
como Futuro<Respuesta>
http también proporciona una clase de cliente HTTP más estándar, client. el cliente admite una conexión
persistente. Será útil cuando se realicen muchas solicitudes a un servidor en particular. Debe cerrarse
correctamente utilizando el método de cierre. De lo contrario, es similar a la clase http. El código de ejemplo es
el siguiente:
114
Machine Translated by Google
Aleteo
Accediendo a ProductserviceAPI
Vamos a crear una aplicación simple para obtener datos de productos de un servidor web y luego mostrar los
productos usando ListView.
aleteo:
activos:
- assets/appimages/floppy.png - assets/
appimages/iphone.png - assets/
appimages/laptop.png - assets/
appimages/pendrive.png - assets/
appimages/pixel.png - assets/appimages/
tablet.png
dependencias:
http: ^0.12.0+2
• Aquí, usaremos la última versión del paquete http. Android Studio enviará una alerta de paquete de que se
actualizó pubspec.yaml.
• Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo
configurará correctamente para la aplicación.
• Cree un nuevo archivo JSON, products.json con la información del producto como se muestra a continuación:
[
{
"name": "iPhone",
"description": "iPhone es el teléfono con estilo de todos los tiempos",
"price": 1000, "image": "iphone.png"
},
{
"name": "Pixel",
"description": "Pixel es el teléfono con más funciones", "price": 800,
"image": "pixel.png"
115
Machine Translated by Google
Aleteo
},
{
"name": "Laptop",
"description": "Laptop es la herramienta de desarrollo más productiva", "price": 2000,
"image": "laptop.png"
},
{
"name": "Tablet",
"description": "Tablet es el dispositivo más útil para reuniones", "price": 1500, "image": "tablet.png"
},
{
"name": "Pendrive",
"description": "Pendrive es un medio de almacenamiento útil", "price": 100,
"image": "pendrive.png"
},
{
"name": "Unidad de disquete",
"descripción": "La unidad de disquete es un medio de almacenamiento de rescate útil",
"price": 20, "image": "floppy.png"
}
]
• Ejecute cualquier servidor web con JSONWebServer como su directorio raíz y obtenga su ruta web.
Por ejemplo, http://192.168.184.1:8000/products.json. Podemos usar cualquier servidor web como apache, nginx,
etc.,
• La forma más sencilla es instalar una aplicación de servidor http basada en nodos. Siga los pasos dados
a continuación para instalar y ejecutar la aplicación del servidor http.
cd /ruta/a/JSONWebServer
116
Machine Translated by Google
Aleteo
http://127.0.0.1:8000
Presione CTRL-C para detener el servidor
• Cree un nuevo archivo, Product.dart en la carpeta lib y mueva la clase Product a él.
• Escriba un constructor de fábrica en la clase Product, Product.fromMap para convertir Map de datos
asignados en el objeto Product. Normalmente, el archivo JSON se convertirá en un objeto Dart
Map y luego se convertirá en un objeto relevante (Producto)
Product(datos['nombre'],
datos['descripción'],
datos['precio'],
datos['imagen'], );
}
clase Producto
{ cadena final nombre;
descripción final de la cadena;
precio internacional final; imagen
de cadena final;
}
}
• Escriba dos métodos, parseProducts y fetchProducts, en la clase principal para obtener y cargar la
información del producto del servidor web en el objeto List<Producto>.
if (respuesta.statusCode == 200) {
return parseProducts(respuesta.cuerpo); } else
{ throw Exception('No se pueden obtener
productos de la API REST');
117
Machine Translated by Google
Aleteo
}
}
• El futuro se utiliza para la carga diferida de la información del producto. Lazy loading es un concepto
para diferir la ejecución del código hasta que sea necesario.
• json.decode se usa para decodificar los datos JSON en el objeto Dart Map. Una vez que se
decodifican los datos JSON, se convertirán en List<Product> usando fromMap de la clase Product.
• En la clase MyApp, agregue una nueva variable miembro, productos de tipo Future<Product> e
inclúyala en el constructor.
...
casa: MiPáginaInicio(
título: 'Página de inicio de demostración de navegación del producto',
productos: productos),
• Cree un nuevo widget, ProductBoxList para crear la lista de productos en la página de inicio.
118
Machine Translated by Google
Aleteo
@override
Widget build (contexto BuildContext) { return
ListView.builder(
itemCount: items.length,
itemBuilder: (contexto, índice) { return
GestureDetector( child: ProductBox(item:
items[index]), onTap: () { Navigator.push( context,
MaterialPageRoute(
}
}
Tenga en cuenta que usamos el mismo concepto que se usa en la aplicación de navegación para listar el
producto, excepto que está diseñado como un widget separado al pasar productos (objeto) de tipo List<Product>.
if (instantánea.hasError) print(instantánea.error);
devolver instantánea.hasData ?
ProductBoxList(items:
snapshot.data) // devuelve el widget ListView
: Centro (hijo: CircularProgressIndicator());
}, ), ));
}
• Tenga en cuenta que usamos el widget FutureBuilder para representar el widget. FuturoConstructor
intentará obtener los datos de su propiedad futura (de tipo Future<List<Product>>).
Si la propiedad futura devuelve datos, representará el widget utilizando ProductBoxList; de lo
contrario, arrojará un error.
119
Machine Translated by Google
Aleteo
importar 'dardo:
asíncrono'; importar 'dardo:
convertir'; importar 'paquete:http/http.dart' como http;
importar 'Producto.dardo';
if (respuesta.statusCode == 200) {
return parseProducts(respuesta.cuerpo); }
else { throw Exception('No se pueden obtener
productos de la API REST');
}
}
return MaterialApp(título:
'Flutter Demo', theme:
ThemeData(primarySwatch:
Colors.blue, ), home:
MyHomePage(título: 'Product
Navigation demo home page',
products: products), );
}
}
120
Machine Translated by Google
Aleteo
@anular
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title: Text("Product
Navigation")), body: Center( child:
FutureBuilder<List<Product>>( future: products, builder: (context,
snapshot) {
if (instantánea.hasError) print(instantánea.error);
devolver instantánea.hasData ?
ProductBoxList(items:
snapshot.data) // devuelve el widget ListView
: Centro (hijo: CircularProgressIndicator());
}, ), ));
}
}
@override
Widget build (contexto BuildContext) { return
ListView.builder(
itemCount: items.length,
itemBuilder: (contexto, índice) { return
GestureDetector( child:
ProductBox(item: items[index]), onTap: ()
{ Navigator.push( context, MaterialPageRoute(
}
}
@anular
Creación de widgets (contexto BuildContext)
{ return Scaffold (
121
Machine Translated by Google
Aleteo
appBar:
AppBar( título:
Texto(este.elemento.nombre), ),
cuerpo: Centro( hijo: Contenedor( relleno:
EdgeInsets.all(0), hijo:
Columna( 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,
niños: <Widget>[
Text(this.item.name, style:
TextStyle(fontWeight:
Peso de la fuente.negrita)),
Text(this.item.description),
Text("Precio: " + this.item.price.toString()), RatingBox(), ], )))
]),
), ), );
}
}
void _setRatingAsOne()
{ setState(() { _rating = 1; });
void _setRatingAsTwo()
{ setState(() { _rating = 2; });
void _setRatingAsThree()
{ setState(() {
122
Machine Translated by Google
Aleteo
_puntuación =
3; });
}
return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, children: <Widget>[ Container( padding:
EdgeInsets.all(0), child: IconButton(
123
Machine Translated by Google
Aleteo
:
Icon( Icons.star_border,
size: _size, )), color:
Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size, ), ), ], );
}
}
Text(this.item.name,
style: TextStyle(fontWeight:
Peso de la fuente.negrita)),
Text(this.item.description),
Text("Precio: " + this.item.price.toString()), RatingBox(), ], )))
]),
));
}
}
Finalmente ejecute la aplicación para ver el resultado. Será igual que nuestro ejemplo de Navegación ,
excepto que los datos son de Internet en lugar de datos estáticos locales ingresados al codificar la
aplicación.
124
Machine Translated by Google
Aleteo
15. Flutter – Conceptos de base de datos
Flutter proporciona muchos paquetes avanzados para trabajar con bases de datos. Los paquetes más importantes son:
• firebase_database: se utiliza para acceder y manipular la base de datos NoSQL alojada en la nube
de Google.
SQLite
La base de datos SQLite es el motor de base de datos integrado basado en SQL estándar y de facto. Es un motor de
base de datos pequeño y probado en el tiempo. El paquete sqflite proporciona una gran cantidad de funciones para
trabajar de manera eficiente con la base de datos SQLite. Proporciona métodos estándar para manipular el motor de
base de datos SQLite. La funcionalidad principal proporcionada por el paquete sqflite es la siguiente:
• Métodos de consulta avanzados (método de consulta) para reducir al código requerido para consultar y
obtener información de la base de datos SQLite.
Vamos a crear una aplicación de producto para almacenar y obtener información de productos de un motor de base de
datos SQLite estándar usando el paquete sqflite y entender el concepto detrás de la base de datos SQLite y el paquete
sqflite.
aleteo:
activos:
- activos/imágenes de la aplicación/disquete.png
- activos/imágenes de la aplicación/iphone.png
- activos/imágenes de la aplicación/portátil.png
- activos/imágenes de la aplicación/pendrive.png
- activos/imágenes de la aplicación/pixel.png
- activos/imágenes de la aplicación/tableta.png
dependencias:
sqflite: cualquiera
125
Machine Translated by Google
Aleteo
dependencias:
ruta_proveedor: cualquiera
• Aquí, el paquete path_provider se usa para obtener la ruta de la carpeta temporal del sistema y la ruta de la
aplicación. Use el número de versión más reciente de sqflite en lugar de cualquiera.
• Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo configurará
correctamente para la aplicación.
• En la base de datos, necesitamos la clave principal, la identificación como campo adicional junto con las
propiedades del Producto como el nombre, el precio, etc. Por lo tanto, agregue la propiedad de identificación
en la clase Producto. Además, agregue un nuevo método, toMap para convertir un objeto de producto en un
objeto de mapa. fromMap y toMap se utilizan para serializar y deserializar el objeto Producto y se utiliza en
métodos de manipulación de bases de datos.
clase Producto { id
int final; nombre
final de la cadena;
descripción final de la cadena;
precio internacional final; imagen
de cadena final;
• Cree un nuevo archivo, Database.dart en la carpeta lib para escribir la funcionalidad relacionada con SQLite .
126
Machine Translated by Google
Aleteo
importar 'Producto.dardo';
• ruta se utiliza para acceder a la función de la utilidad dart core relacionada con las rutas de archivo.
clase SQLiteDbProvider
{ SQLiteDbProvider._();
SQLiteDBProvoider.db.<método>
• Crear un método para obtener la base de datos (opción Future) de tipo Future<Database>.
Cree una tabla de productos y cargue los datos iniciales durante la creación de la propia base de datos.
initDB() asíncrono {
Directorio documentosDirectorio = esperar
getApplicationDocumentsDirectory(); String path =
join(documentsDirectory.path, "ProductDB.db"); regresar esperar openDatabase (ruta,
versión: 1,
127
Machine Translated by Google
Aleteo
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone es el teléfono con más estilo", 1000,
"iphone.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel es el teléfono con más funciones de la historia", 800,
"píxel.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[3, "Laptop", "Laptop es la herramienta de desarrollo más productiva",
2000, "portátil.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[4, "Tablet", "La computadora portátil es la herramienta de desarrollo más productiva",
1500, "tableta.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive es un medio de almacenamiento útil", 100,
"pendrive.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[6, "Unidad de disquete", "La unidad de disquete es un medio de
almacenamiento de rescate útil", 20, "floppy.png"]);
});
}
• unirse : se utiliza para crear una ruta específica del sistema. Lo hemos usado para crear una base de datos.
sendero.
128
Machine Translated by Google
Aleteo
• onCreate : se usa para escribir código mientras se crea una base de datos por primera vez
• db.execute : se utiliza para ejecutar consultas SQL. Acepta una consulta. Si la consulta tiene
marcador de posición (?), luego acepta valores como lista en el segundo argumento.
devolución de productos;
}
• Método de consulta utilizado para obtener toda la información del producto. consulta proporciona un acceso directo
para consultar la información de una tabla sin escribir toda la consulta. El método de consulta generará la
consulta adecuada utilizando nuestra entrada como columnas, orderBy, etc.,
• Se usó el método fromMap del producto para obtener detalles del producto mediante un bucle de los resultados.
objeto, que contiene todas las filas de la tabla.
• Crear tres métodos: método de inserción, actualización y eliminación para insertar, actualizar y eliminar productos
de la base de datos
129
Machine Translated by Google
Aleteo
var id = maxIdResult.first["last_inserted_id"];
resultado devuelto;
}
resultado devuelto;
}
importar 'Producto.dardo';
clase SQLiteDbProvider
{ SQLiteDbProvider._();
initDB() asíncrono {
130
Machine Translated by Google
Aleteo
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone es el teléfono con más estilo", 1000,
"iphone.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel es el teléfono con más funciones de la historia", 800,
"píxel.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[3, "Laptop", "Laptop es la herramienta de desarrollo más productiva",
2000, "portátil.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[4, "Tablet", "La computadora portátil es la herramienta de desarrollo más productiva",
1500, "tableta.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive es un medio de almacenamiento útil", 100,
"pendrive.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[6, "Unidad de disquete", "La unidad de disquete es un medio de
almacenamiento de rescate útil", 20, "floppy.png"]);
});
}
131
Machine Translated by Google
Aleteo
devolución de productos;
}
resultado devuelto;
}
resultado devuelto;
}
132
Machine Translated by Google
Aleteo
}
}
vacío principal() {
runApp(MyApp(productos: SQLiteDbProvider.db.getAllProducts()));
}
• Aquí, hemos utilizado el método getAllProducts para obtener todos los productos de la base de datos.
• Ejecute la aplicación y vea los resultados. Será similar al ejemplo anterior, Acceder a la API del servicio del
producto, excepto que la información del producto se almacena y se obtiene de la base de datos SQLite
local.
Firebase es una plataforma de desarrollo de aplicaciones BaaS. Proporciona muchas características para acelerar el
desarrollo de aplicaciones móviles como servicio de autenticación, almacenamiento en la nube, etc. Una de las
características principales de Firebase es Cloud Firestore, una base de datos NoSQL en tiempo real basada en la nube.
Flutter proporciona un paquete especial, cloud_firestore para programar con Cloud Firestore. Vamos a crear
una tienda de productos en línea en Cloud Firestore y crear una aplicación para acceder a la tienda de
productos.
producto de clase {
nombre final de la cadena;
descripción final de la cadena;
precio internacional final;
imagen de cadena final;
aleteo:
133
Machine Translated by Google
Aleteo
activos:
- activos/imágenes de la aplicación/disquete.png
- activos/imágenes de la aplicación/iphone.png
- activos/imágenes de la aplicación/portátil.png
- activos/imágenes de la aplicación/pendrive.png
- activos/imágenes de la aplicación/pixel.png
- activos/imágenes de la aplicación/tableta.png
dependencias:
tienda_de_fuego_en_la_nube: ^0.9.13+1
• Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo configurará correctamente
para la aplicación.
• Una vez que se crea la cuenta de Firebase, se redirigirá a la página de descripción general del proyecto. Enumera todos
los proyectos basados en Firebase y proporciona una opción para crear un nuevo proyecto.
• Ingrese la base de datos de la aplicación de productos como nombre del proyecto y haga clic en la opción Crear proyecto.
• Haga clic en Resumen del proyecto. Abre la página de descripción general del proyecto.
• Haga clic en el icono de Android. Se abrirá la configuración del proyecto específica para el desarrollo de Android.
• Haga clic en Registrar aplicación. Genera un archivo de configuración del proyecto, google_service.json
• Descargue google_service.json y luego muévalo al directorio android/app del proyecto. Este archivo es la conexión entre
nuestra aplicación y Firebase.
134
Machine Translated by Google
Aleteo
buildscript
{ repositorios { // ...
dependencias
{ // ...
classpath 'com.google.gms:google-services:3.2.1' // nuevo
}
}
android
{ configuración predeterminada {
...
multiDexEnabled verdadero
}
...
}
dependencias {
...
compilar 'com.android.support: multidex:1.0.3'
}
Esta dependencia permite que la aplicación de Android use la funcionalidad de dex múltiple.
• Cree una tienda de productos en el proyecto recién creado siguiendo los siguientes pasos:
• Haz clic en Agregar colección. Ingrese el producto como nombre de la colección y luego haga clic en Siguiente.
135
Machine Translated by Google
Aleteo
• Agregar información adicional del producto usando las opciones Agregar documento .
• Abra el archivo main.dart e importe el archivo del complemento Cloud Firestore y elimine el paquete http.
importar 'paquete:cloud_firestore/cloud_firestore.dart';
• Cloud Firestore proporciona la colección a través del concepto Dart Stream y, por lo tanto, modifica el tipo de
productos en el widget MyApp y MyHomePage de Future<list<Product>> a Stream<QuerySnapshot>.
136
Machine Translated by Google
Aleteo
• Cambie el método de compilación del widget MyHomePage para usar StreamBuilder en lugar de
Constructor de Futuro.
@anular
Widget build(BuildContext context) { return
Scaffold(appBar: AppBar(title: Text("Product
Navigation")), body: Center( child:
StreamBuilder<QuerySnapshot>( stream: products, builder:
(context, snapshot) {
if (instantánea.hasError) print(instantánea.error);
if(snapshot.hasData)
{ List<DocumentSnapshot> documentos = snapshot.data.documents;
List<Producto> artículos = List<Producto>();
items.add(Producto.fromMap(documento.datos));
}
} }, ), ));
137
Machine Translated by Google
Hoy en día, las aplicaciones móviles son utilizadas por clientes de diferentes países y, como resultado, se requieren
aplicaciones para mostrar el contenido en diferentes idiomas. Permitir que una aplicación funcione en varios idiomas se
denomina internacionalización de la aplicación.
Para que una aplicación funcione en diferentes idiomas, primero debe encontrar la configuración regional actual del sistema
en el que se ejecuta la aplicación y luego debe mostrar su contenido en esa configuración regional en particular, y este
proceso se denomina Localización.
Flutter framework proporciona tres clases base para la localización y amplias clases de utilidad derivadas de las clases
base para localizar una aplicación.
• Configuración regional: la configuración regional es una clase utilizada para identificar el idioma del usuario. Por ejemplo, en-us
identifica el inglés americano y se puede crear como:
• Localizaciones: las localizaciones son un widget genérico que se utiliza para establecer la configuración
regional y los recursos localizados de su hijo.
138
Machine Translated by Google
Aleteo
• Aquí, CustomLocalizations es una nueva clase personalizada creada específicamente para obtener cierto
contenido localizado (título y mensaje) para el widget. of utiliza la clase Localizations para devolver una nueva
clase CustomLocalizations.
@anular
bool isSupported(Locale locale) => ['en',
'es'].contains(locale.languageCode);
• load: acepta una configuración regional y comienza a cargar los recursos para la configuración regional
especificada.
@anular
Future<CustomLocalizations> load(Locale locale) {
regreso
SynchronousFuture<LocalizacionesPersonalizadas>(LocalizacionesPersonalizadas(locale));
}
@anular
bool shouldReload(CustomLocalizationsDelegate old) => false;
@anular
bool es compatible => ['en',
'es'].contains(locale.languageCode);
@anular
Future<CustomLocalizations> load(Locale locale) {
regreso
SynchronousFuture<LocalizacionesPersonalizadas>(LocalizacionesPersonalizadas(locale));
139
Machine Translated by Google
Aleteo
@anular
bool shouldReload(CustomLocalizationsDelegate old) => false;
}
En general, las aplicaciones de Flutter se basan en dos widgets de nivel raíz, MaterialApp o WidgetsApp.
Flutter proporciona localización preparada para ambos widgets y son MaterialLocalizations y
WidgetsLocaliations. Además, Flutter también proporciona delegados para cargar MaterialLocalizations y
GlobalMaterialLocalizations.delegate respectivamente.WidgetsLocaliations y ellos y son
GlobalWidgetsLocalizations.delegate
Vamos a crear una aplicación sencilla habilitada para la internacionalización para probar y comprender el
concepto.
dependencias:
aleteo:
SDK: aleteo
flutter_localizaciones:
SDK: aleteo
• Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo
configurará correctamente para la aplicación.
140
Machine Translated by Google
Aleteo
}, };
@override
bool isSupported(Locale locale) => ['en',
'es'].contains(locale.languageCode);
@anular
Future<CustomLocalizations> load(Locale locale) {
regreso
SynchronousFuture<LocalizacionesPersonalizadas>(LocalizacionesPersonalizadas(locale));
}
@override
bool shouldReload(CustomLocalizationsDelegate old) => false;
}
localizationsDelegates: [ const
CustomLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
configuraciones regionales
admitidas: [ const Locale('en', ''),
141
Machine Translated by Google
Aleteo
• Utilice el método CustomLocalizations para obtener el valor localizado del título y el mensaje
y utilícelo en el lugar apropiado como se especifica a continuación:
@anular
Compilación del widget (contexto BuildContext) {
andamio de vuelta(
barra de aplicaciones: barra de aplicaciones (
• Cerrar la aplicación. Vaya a Configuración -> Sistema -> Idiomas y entrada ->
Idiomas*
• Haz clic en Agregar una opción de idioma y selecciona Español. Esto instalará el idioma español y
luego lo listará como una de las opciones.
• Seleccione Español y muévalo arriba de Inglés. Esto establecerá como primer idioma el español y
todo se cambiará a texto en español.
142
Machine Translated by Google
Aleteo
Vamos a crear una nueva aplicación localizada utilizando el paquete intl y entender el concepto.
dependencias:
aleteo:
SDK: aleteo
flutter_localizaciones: sdk:
flutter
intl: ^0.15.7
intl_translation: ^0.17.3
143
Machine Translated by Google
Aleteo
• Android Studio mostrará la alerta como se muestra a continuación informando que pubspec.yaml
se actualiza
• Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo
configurará correctamente para la aplicación.
devuelve initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName; return
CustomLocalizations(); });
}
}
@anular
144
Machine Translated by Google
Aleteo
@anular
Future<CustomLocalizations> load(Locale locale) {
devuelve CustomLocalizations.load(locale);
}
@anular
bool shouldReload(CustomLocalizationsDelegate old) => false;
}
• Aquí, hemos usado tres métodos del paquete intl en lugar de métodos personalizados.
De lo contrario, los conceptos son los mismos.
importar 'l10n/messages_all.dart';
• Abra un símbolo del sistema y vaya al directorio raíz de la aplicación (donde pubspec.yaml
está disponible) y ejecute el siguiente comando:
• Aquí, el comando generará un archivo intl_message.arb, una plantilla para crear un mensaje en una
configuración regional diferente. El contenido del archivo es el siguiente:
{
"@@last_modified": "2019-04-19T02:04:09.627551",
"título": "Demostración",
"@título": {
"description": "Título de la aplicación de demostración",
"teclee el texto",
"marcadores de posición": {}
},
"mensaje": "Hola Mundo",
"@mensaje": {
"description": "Mensaje para la aplicación de demostración",
"teclee el texto",
"marcadores de posición": {}
}
}
• Copie intl_message.arb y cree un nuevo archivo, intl_es.arb y cambie el contenido al idioma español
como se muestra a continuación:
145
Machine Translated by Google
Aleteo
{
"@@last_modified": "2019-04-19T02:04:09.627551", "title":
"Manifestación", "@title": { "description": "Título para la
aplicación Demo", "type": "text ", "marcadores de posición":
{} }, "mensaje": "Hola Mundo", "@mensaje": {
}
}
• Ahora, ejecute el siguiente comando para crear el archivo de mensaje final, message_all.dart
146
Machine Translated by Google
La prueba es una fase muy importante en el ciclo de vida de desarrollo de una aplicación. Asegura que la
aplicación es de alta calidad. Las pruebas requieren una cuidadosa planificación y ejecución. También es la
fase del desarrollo que consume más tiempo.
El lenguaje Dart y el marco Flutter brindan un amplio soporte para la prueba automatizada de una aplicación.
Tipos de pruebas
Generalmente, hay tres tipos de procesos de prueba disponibles para probar completamente una aplicación.
Son los siguientes:
Examen de la unidad
La prueba unitaria es el método más fácil para probar una aplicación. Se basa en asegurar la corrección de
un fragmento de código (una función, en general) o un método de una clase. Pero, no refleja el entorno real
y, en consecuencia, es la opción de menor importancia para encontrar los errores.
Prueba de widgets
Pruebas de integración
Las pruebas de integración involucran tanto pruebas unitarias como pruebas de widgets junto con
componentes externos de la aplicación como base de datos, servicio web, etc. Simula o se burla del entorno
real para encontrar casi todos los errores, pero es el proceso más complicado.
Flutter brinda soporte para todo tipo de pruebas. Brinda soporte extenso y exclusivo para pruebas de widgets.
En este capítulo, discutiremos las pruebas de widgets en detalle.
Prueba de widgets
El marco de prueba de Flutter proporciona el método testWidgets para probar widgets. Acepta dos argumentos:
• Descripción de la prueba
• código de prueba
147
Machine Translated by Google
Aleteo
Pasos involucrados
La prueba de widgets implica tres pasos distintos:
• WidgetTester es la clase proporcionada por el marco de prueba de Flutter para construir y renderizar el
widget. El método pumpWidget de la clase WidgetTester acepta cualquier widget y lo representa en el
entorno de prueba.
• Flutter framework proporciona muchas opciones para encontrar los widgets representados en el entorno
de prueba y generalmente se denominan Finders. Los buscadores más utilizados son find.text,
find.byKey y find.byWidget
• find.text encuentra el widget que contiene el texto especificado.
find.text('Hola')
encontrar.byKey('inicio')
find.byWidget(homeWidget)
• Flutter framework proporciona muchas opciones para hacer coincidir el widget con el widget esperado
y normalmente se denominan Matchers. Podemos usar el método esperado proporcionado por el marco
de prueba para hacer coincidir el widget, que encontramos en el segundo paso con nuestro widget
esperado al elegir cualquiera de los emparejadores. Algunos de los emparejadores importantes son los
siguientes:
expect(find.text('Hola'), encuentraUnWidget);
148
Machine Translated by Google
Aleteo
expect(find.text('Guardar'), encuentraWidgets);
expect(find.text('Guardar'), findsNWidgets(2));
),
));
expect(find.text('Hola'), encuentraUnWidget);
});
Aquí, representamos un widget de MaterialApp con el texto Hola usando el widget de texto en su cuerpo.
Luego, usamos find.text para encontrar el widget y luego lo emparejamos usando findsOneWidget.
Ejemplo de trabajo
Vamos a crear una aplicación de aleteo simple y escribir una prueba de widget para comprender mejor los
pasos involucrados y el concepto.
• Abra widget_test.dart en la carpeta de prueba. Tiene un código de prueba de muestra como se indica a continuación:
149
Machine Translated by Google
Aleteo
• Toquemos nuevamente el botón de incremento del contador y luego verifiquemos si el contador aumenta
a dos.
await tester.tap(find.byIcon(Icons.add));
esperar probador.bomba();
expect(find.text('2'), encuentraUnWidget);
• Haga clic en pruebas en la opción widget_test.dart. Esto ejecutará la prueba e informará el resultado en
la ventana de resultados.
150
Machine Translated by Google
Este capítulo explica cómo implementar la aplicación Flutter en las plataformas Android e iOS.
Aplicación Android
• Cambie el nombre de la aplicación usando la entrada android:label en el archivo de manifiesto de Android.
El archivo de manifiesto de la aplicación Android, AndroidManifest.xml se encuentra en <directorio de la aplicación>/
android/app/src/main. Contiene detalles completos sobre una aplicación de Android.
Podemos configurar el nombre de la aplicación usando la entrada android:label.
cd /ruta/a/mi/aplicación
aleteo construir apk
instalación de aleteo
Aplicación iOS
• Registre la aplicación iOS en App Store Connect utilizando el método estándar. Guarde el ID de paquete utilizado
al registrar la aplicación.
• Actualice el nombre para mostrar en la configuración del proyecto XCode para establecer el nombre de la aplicación.
151
Machine Translated by Google
Aleteo
• Actualice el identificador del paquete en la configuración del proyecto XCode para establecer la identificación del paquete, que
utilizado en el paso 1.
• Agregue un nuevo ícono de aplicación según sea necesario utilizando el método estándar.
152
Machine Translated by Google
Aleteo
19. Flutter – Herramientas de desarrollo
Este capítulo explica en detalle las herramientas de desarrollo de Flutter. La primera versión estable del kit de herramientas
de desarrollo multiplataforma se lanzó el 4 de diciembre de 2018, Flutter 1.0.
Bueno, Google está trabajando continuamente en las mejoras y fortaleciendo el marco Flutter con diferentes herramientas
de desarrollo.
Conjuntos de widgets
Google actualizó los conjuntos de widgets de Material y Cupertino para proporcionar una calidad de píxeles perfecta en el
diseño de los componentes. La próxima versión de flutter 1.2 se diseñará para admitir eventos de teclado de escritorio y
compatibilidad con el desplazamiento del mouse.
Visual Studio Code es compatible con el desarrollo flutter y proporciona accesos directos extensos para un desarrollo rápido
y eficiente. Algunas de las funciones clave proporcionadas por Visual Studio Code para el desarrollo de flutter se enumeran
a continuación:
• Asistencia de código: cuando desee comprobar las opciones, puede utilizar Ctrl+Espacio para obtener una
lista de opciones de finalización de código.
• Solución rápida - Ctrl+. es una herramienta de solución rápida para ayudar a corregir el código.
• Atajos de depuración.
• Reinicios en caliente
Dart DevHerramientas
Podemos usar Android Studio o Visual Studio Code, o cualquier otro IDE para escribir nuestro código e instalar
complementos. El equipo de desarrollo de Google ha estado trabajando en otra herramienta de desarrollo llamada Dart
DevTools. Es una suite de programación basada en web. Es compatible con las plataformas Android e iOS. Se basa en la
vista de línea de tiempo para que los desarrolladores puedan analizar fácilmente sus aplicaciones.
Resolviendo dependencias...
+ argumentos 1.5.1
+ asíncrono 2.2.0
153
Machine Translated by Google
Aleteo
+ js 0.6.1 + 1 +
meta 1.1.7
+ mimo 0.9.6+2
..................
..................
Ejecutar servidor
Comience su aplicación
http://localhost:9100/?port=9200
154
Machine Translated by Google
Aleteo
SDK de aleteo
Para actualizar Flutter SDK, use el siguiente comando:
actualización de aleteo
Inspector de aleteo
Se utiliza para explorar árboles de widgets de aleteo. Para lograr esto, ejecute el siguiente comando en
su consola,
155
Machine Translated by Google
Aleteo
Para recargar en caliente los cambios mientras se ejecuta, presione "r". Para reiniciar en caliente (y reconstruir el estado),
presione "R".
Un depurador y perfilador de Observatory en iPhone X está disponible en: http://127.0.0.1:50399/
Para un mensaje de ayuda más detallado, presione "h". Para separar, presione "d"; para salir, presione "q".
156
Machine Translated by Google
Aleteo
20. Flutter: escritura de aplicaciones avanzadas
En este capítulo, vamos a aprender cómo escribir una aplicación móvil completa, cost_calculator. El propósito de
la calculadora_gastos es almacenar nuestra información de gastos. La característica completa de la aplicación es
la siguiente:
• Lista de gastos
Vamos a programar la aplicación de calculadora de gastos utilizando las funciones avanzadas mencionadas a
continuación del marco Flutter.
• Programación de formularios
dependencias:
aleteo:
SDK: aleteo
sqflite: ^1.1.0
path_provider: ^0.5.0+1
scoped_model: ^1.0.1 intl:
cualquiera
• Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo configurará
correctamente para la aplicación.
157
Machine Translated by Google
Aleteo
• Agregue un archivo nuevo, Expense.dart para crear una clase de gastos. La clase de gastos tendrá las
siguientes propiedades y métodos.
• propiedad: id: identificación única para representar una entrada de gastos en la base de datos SQLite.
);
}
• toMap : se usa para convertir el objeto de gastos en Dart Map, que se puede usar más en la
programación de bases de datos
gasto de clase { id
int final; cantidad
doble final; fecha final de
fecha y hora; categoría de
cadena final;
158
Machine Translated by Google
Aleteo
DateTime.parse(datos['fecha']),
datos['categoría'] );
• Agregue un nuevo archivo, Database.dart para crear la clase SQLiteDbProvider. El propósito de la clase
SQLiteDbProvider es el siguiente:
• Obtenga todos los gastos disponibles en la base de datos utilizando el método getAllExpenses. Eso
se utilizará para enumerar toda la información de gastos del usuario.
gastos de devolución;
}
159
Machine Translated by Google
Aleteo
• Obtenga los gastos totales del usuario utilizando el método getTotalExpense. Será
se utiliza para mostrar el gasto total actual al usuario.
);
resultado devuelto;
}
160
Machine Translated by Google
Aleteo
importar 'Gastos.dart';
clase SQLiteDbProvider
{ SQLiteDbProvider._();
initDB() asíncrono {
Directorio documentosDirectorio = espera getApplicationDocumentsDirectory(); String path =
join(documentsDirectory.path, "ExpenseDB2.db"); return await openDatabase (ruta, versión:
1, onOpen: (db) {}, onCreate: (Base de datos db, versión int) asíncrono {
await
db.execute( "INSERTAR EN Gastos ('id', 'cantidad', 'fecha', 'categoría') valores
(?, ?, ?, ?)", [1, 1000, '2019-04-01 10 :00:00', "Comida"]);
/*esperar
db.execute( "INSERTAR EN EL Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel es el teléfono con más funciones de la historia", 800,
161
Machine Translated by Google
Aleteo
"píxel.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[3, "Laptop", "La computadora portátil es la herramienta de desarrollo más productiva",
2000, "laptop.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[4, "Tablet", "La computadora portátil es la herramienta de desarrollo más productiva",
1500, "tablet.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[5, "Pendrive", "iPhone es el teléfono con estilo de todos los tiempos", 100,
"pendrive.png"]);
esperar db.ejecutar(
"INSERTAR EN Producto ('id', 'nombre', 'descripción', 'precio',
'imagen') valores (?, ?, ?, ?, ?)",
[6, "Floppy Drive", "iPhone es el teléfono con más estilo", 20, "floppy.png"]);
*/
});
}
gastos de devolución;
}
162
Machine Translated by Google
Aleteo
var id = maxIdResult.first["last_inserted_id"];
resultado devuelto;
}
• Aquí,
• Cree un archivo nuevo, ExpenseListModel.dart para crear ExpenseListModel. El propósito del modelo es
mantener la información completa de los gastos del usuario en la memoria y actualizar la interfaz de usuario
de la aplicación cada vez que cambia el gasto del usuario en la memoria. Se basa en la clase Model del
paquete scoped_model. Tiene las siguientes propiedades y métodos:
163
Machine Translated by Google
Aleteo
importe devuelto;
}
• load: se utiliza para cargar los gastos completos de la base de datos y en la variable _items.
También llama a notificarListeners para actualizar la interfaz de usuario.
void load()
{ Future<List<Expense>> list = SQLiteDbProvider.db.getAllExpenses();
}
}
devolver nulo;
}
• agregar: se usa para agregar un nuevo elemento de gasto en la variable _items, así como en la base
de datos. También llama a notificarListeners para actualizar la interfaz de usuario.
• agregar: se usa para agregar un nuevo elemento de gasto en la variable _items, así como en la base de
datos. También llama a notificarListeners para actualizar la interfaz de usuario.
164
Machine Translated by Google
Aleteo
}
}
• eliminar: se utiliza para eliminar un elemento de gasto existente en la variable _items, así como
de la base de datos También llama a notificarListeners para actualizar la interfaz de usuario.
}
}
ExpenseListModel() { this.load(); }
165
Machine Translated by Google
Aleteo
importe devuelto;
}
void load()
{ Future<List<Expense>> list =
SQLiteDbProvider.db.getAllExpenses();
}
}
devolver nulo;
}
}
}
166
Machine Translated by Google
Aleteo
}
}
importar 'Gastos.dart';
void main()
{ gastos finales = ExpenseListModel();
runApp(ScopedModel<ExpenseListModel>( modelo:
gastos, niño: MiAplicación(), ));
• Aquí,
• objeto de gastos carga toda la información de gastos del usuario de la base de datos.
Además, cuando la aplicación se abre por primera vez, creará la base de datos
necesaria con las tablas adecuadas.
return MaterialApp(título:
'Gasto', tema:
ThemeData(
167
Machine Translated by Google
Aleteo
}
}
• Cree el widget MyHomePage para mostrar toda la información de gastos del usuario junto con los gastos
totales en la parte superior. El botón flotante en la esquina inferior derecha se usará para agregar nuevos
gastos.
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title: Text(this.title), ),
body:
ScopedModelDescendant<ExpenseListModel>( builder:
(contexto, hijo, gastos) { return ListView.separated(
); } más
{ índice = índice - 1;
return Desechable( clave:
Clave(gastos.elementos[índice].id.toString()), onDesechado:
(dirección) {
gastos.eliminar(gastos.artículos[índice]);
Scaffold.of(contexto).showSnackBar(SnackBar( contenido:
+
Texto("Artículo con id, " gastos.artículos[índice].id.toString()
+
"se despide")));
},
child: ListTile( onTap:
()
{ Navigator.push( context,
MaterialPageRoute( builder: (context) =>
FormPage( id:
gastos.artículos[índice].id,
168
Machine Translated by Google
Aleteo
},
inicial: icono (Icons.monetization_on), final: Icon
(Icons.keyboard_arrow_right),
título: Texto(gastos.artículos[índice].categoría
+
": " +
Navigator.push( contexto,
MaterialPageRoute( constructor:
(contexto) => ScopedModelDescendant<ExpenseListModel>(
constructor: (contexto, hijo, gastos) { return
FormPage( id: 0,
'Comida'));
// imprimir(gastos.artículos.longitud); },
información sobre herramientas: 'Incremento',
hijo: Icon(Icons.add), ); }));
}
}
• Aquí,
169
Machine Translated by Google
Aleteo
• El widget descartable se usa para eliminar la entrada de gastos con un gesto de deslizar.
• Navegador se utiliza para abrir la interfaz de edición de una entrada de gastos. Puede ser activado por
tocando una entrada de gastos.
• Crear un widget FormPage. El propósito del widget FormPage es agregar o actualizar una entrada de
gastos. También maneja la validación de la entrada de gastos.
identificación
interna final; gastos finales de ExpenseListModel;
@anular
_FormPageState createState() => _FormPageState(id: id, gastos: gastos); }
identificación
interna final; gastos finales de ExpenseListModel;
doble _cantidad;
FechaHora _fecha;
Cadena _categoría;
vacío _enviar() {
formulario final = formKey.currentState;
if (formulario.validar())
{ formulario.guardar();
si (este.id == 0)
gastos.add(Gasto(0, _cantidad, _fecha, _categoría)); else
gastos.update(Expense(this.id, _amount, _date, _category));
Navigator.pop(contexto);
}
}
@anular
Creación de widgets (contexto BuildContext)
{ return Scaffold (
clave: scaffoldKey,
appBar: AppBar(título:
Texto('Ingresar detalles de gastos'),
170
Machine Translated by Google
Aleteo
),
cuerpo: Relleno
(relleno: const EdgeInsets.all (16.0), niño:
Formulario (clave: formKey, niño: Columna
(niños: [TextFormField (estilo: TextStyle
(fontSize: 22), decoración: const
InputDecoration (icono: const
Icon(Icons.monetization_on), labelText:
'Cantidad', labelStyle: TextStyle(fontSize:
18)),
validador: (val) {
Patrón patrón = r'^[1-9]\d*(\.\d+)?$'; RegExp
expresión regular = new RegExp(patrón); if (!
regex.hasMatch(val)) devuelve 'Ingrese un número
válido'; demás
devolver nulo;
},
valor inicial:
identificación == 0 ? '' : gastos.byId(id).amount.toString(), onSaved: (val)
Patrón patrón =
r'^((?:19|20)\d\d)[- /.](0[1-9]|1[012])[- /.](0[1- 9]| [12][0-9]|3[01])$';
},
onSaved: (val) => _date = DateTime.parse(val), initialValue:
id == 0 ? '' gastos.byId(id).formattedDate,
: keyboardType:
TextInputType.datetime, ), TextFormField( estilo: TextStyle(fontSize: 22),
decoración: const InputDecoration( icon: const
Icon(Icons.category), labelText:
: gastos.byId(id).category.toString(),
171
Machine Translated by Google
Aleteo
),
RaisedButton( onPressed:
_submit, child: new
Text('Submit'), ), ], ), ), ), );
}
}
• Aquí,
• La propiedad validator de TextFormField se usa para validar el elemento de formulario junto con
Patrones RegEx.
• La función _submit se usa junto con el objeto de gastos para agregar o actualizar los gastos en la
base de datos.
importar 'Gastos.dart';
vacío principal() {
gastos finales = ExpenseListModel();
runApp(ScopedModel<ExpenseListModel>( modelo:
gastos, niño: MiAplicación(), ));
return MaterialApp(título:
'Gastos', tema:
ThemeData(primarioSwatch:
Colors.blue, ), home:
MyHomePage(título: 'Calculadora de gastos'), );
}
}
172
Machine Translated by Google
Aleteo
@override
Widget build(BuildContext context) { return
Scaffold( appBar: AppBar( title: Text(this.title), ),
body:
ScopedModelDescendant<ExpenseListModel>( builder:
(contexto, hijo, gastos) { return ListView.separated(
); } más
{ índice = índice - 1;
return Desechable( clave:
Clave(gastos.elementos[índice].id.toString()), onDesechado:
(dirección) {
gastos.eliminar(gastos.artículos[índice]);
Scaffold.of(context).showSnackBar(SnackBar( content:
Text("Elemento con id, " +
gastos.elementos[índice].id.toString() + " se
descarta")));
},
child: ListTile( onTap:
()
{ Navigator.push( context,
MaterialPageRoute( builder: (context) => FormPage(
id: gastos.artículos[índice].id,
gastos: gastos, )));
},
inicial: Icono (Icons.monetization_on), final: Icon
(Icons.keyboard_arrow_right), título: Texto (gastos.elementos
[índice]. categoría +
": " +
gastos.artículos[índice].cantidad.toString() + " \ngastado
" +
en gastos.artículos[índice].formattedDate, estilo:
} },
separadorBuilder: (contexto, índice) {
173
Machine Translated by Google
Aleteo
volver Divisor(); }, ); }, ),
botón de acción flotante:
ScopedModelDescendant<Modelo
de lista de gastos> (constructor:
(contexto, hijo, gastos) { return
Botón de acción flotante (onPressed: () {
Navigator.push( contexto,
MaterialPageRoute( constructor: (contexto) =>
ScopedModelDescendant<ExpenseListModel>( constructor:
(contexto, niño, gastos) { return FormPage( id: 0,
'Comida'));
// imprimir(gastos.artículos.longitud); },
información sobre herramientas: 'Incremento',
hijo: Icon(Icons.add), ); }));
}
}
identificación
interna final; gastos finales de ExpenseListModel;
@anular
_FormPageState createState() => _FormPageState(id: id, gastos: gastos); }
identificación
interna final; gastos finales de ExpenseListModel;
doble _cantidad;
FechaHora _fecha;
Cadena _categoría;
174
Machine Translated by Google
Aleteo
vacío _enviar() {
formulario final = formKey.currentState;
if (formulario.validar())
{ formulario.guardar();
si (este.id == 0)
gastos.add(Gasto(0, _cantidad, _fecha, _categoría)); else
gastos.update(Expense(this.id, _amount, _date, _category));
Navigator.pop(contexto);
}
}
@anular
Creación de widgets (contexto BuildContext)
{ return Scaffold (
clave: scaffoldKey,
appBar: AppBar(título:
Texto('Ingresar detalles de gastos'), cuerpo:
Padding( relleno: const EdgeInsets.all(16.0), child:
Form( key: formKey, child: Column( children:
[ TextFormField( estilo: TextStyle(fontSize: 22),
decoración: const InputDecoration( icono: const
Icon(Icons.monetization_on), labelText:
'Cantidad', labelStyle: TextStyle(fontSize:
18)),
validador: (val) {
Patrón patrón = r'^[1-9]\d*(\.\d+)?$'; RegExp
expresión regular = new RegExp(patrón); if (!
regex.hasMatch(val)) devuelve 'Ingrese un número
válido'; demás
devolver nulo;
},
valor inicial:
identificación == 0 ? '' : gastos.byId(id).amount.toString(), onSaved:
175
Machine Translated by Google
Aleteo
Patrón patrón =
r'^((?:19|20)\d\d)[- /.](0[1-9]|1[012])[- /.](0[1- 9]| [12][0-9]|3[01])$';
},
onSaved: (val) => _date = DateTime.parse(val), initialValue:
id == 0 ? '' gastos.byId(id).formattedDate,
: keyboardType:
TextInputType.datetime, ), TextFormField( estilo: TextStyle(fontSize: 22),
decoración: const InputDecoration( icon: const
Icon(Icons.category), labelText:
RaisedButton( onPressed:
_submit, child: new
Text('Submit'), ), ], ), ), ), );
}
}
176
Machine Translated by Google
Aleteo
177
Machine Translated by Google
Aleteo
178
Machine Translated by Google
Aleteo
179
Machine Translated by Google
Flutter framework hace un gran trabajo al proporcionar un excelente marco para crear aplicaciones
móviles de una manera verdaderamente independiente de la plataforma. Al proporcionar simplicidad
en el proceso de desarrollo, alto rendimiento en la aplicación móvil resultante, interfaz de usuario
rica y relevante para la plataforma Android e iOS, Flutter framework seguramente permitirá a muchos
nuevos desarrolladores desarrollar aplicaciones móviles de alto rendimiento y con todas las funciones
en el futuro cercano.
180