Flutter Espaciado en Lista de columna

Column, spacing

Cuando queremos un espacio entre los hijos children del widget Column, normalmente usan SizeBox, pero con Wrap se puede usar un atributo para el spaceado entre los hijos

Wrap(
  spacing: 20, // to apply margin in the main axis of the wrap
  runSpacing: 20, // to apply margin in the cross axis of the wrap
  children: <Widget>[
     Text('child 1'),
     Text('child 2')
  ]
)

Flutter box shadow – sombreado

Aplicar sombra a un container con decoration

return Container(
  margin: EdgeInsets.only(left: 30, top: 100, right: 30, bottom: 50),
  height: double.infinity,
  width: double.infinity,
  decoration: BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.only(
      topLeft: Radius.circular(10),
        topRight: Radius.circular(10),
        bottomLeft: Radius.circular(10),
        bottomRight: Radius.circular(10)
    ),
    boxShadow: [
      BoxShadow(
        color: Colors.grey.withOpacity(0.5),
        spreadRadius: 5,
        blurRadius: 7,
        offset: Offset(0, 3), // changes position of shadow
      ),
    ],
  ),
)

Crear librerías comunes entre aplicaciones Flutter

Desarrollando un sistema, que consta de dos apps según el rol del usuario, ( conductor y pasajero, vendedor y comprador, administrador y empleado, etc ), percate que si bien ya puedo desplegar en ambas plataformas, hay partes de la interfaz y la API que se repite, solo la lógica parece única, entonces surge la necesidad de compartir este código común.

La primera solución fue copiar el código en un paquete dentro de lib, pero como esta en desarrollo se repetirá muchas veces ese paso lo cual suena doloroso, así que probare el concepto de cómo compartirlo entre ambas apps.

bueno, al código.

Creamos 3 aplicaciones: Cliente1, Cliente2 y Librería

$ flutter create --org=com.example.cliente1 Cliente1
$ flutter create --org=com.example.cliente2 Cliente2
$ flutter create --org=com.example.libreria Libreria

Trabajaré en la aplicación Cliente1 agregando la librería y luego repetiré lo mismo en la Cliente2 para comprobarlo.

Lo que necesito probar en este caso es :
– Si se puede compartir widgets
– Si la librería tiene dependencias, estas deben cargarse en la principal o se puede obviar.
– Si se puede configurar variables en la librería desde el cliente.

Tomando el caso del sistema, una parte común entre ambas apps, es el chat.

Primero trabajaremos en la librería

Librería

Para probar cada requerimiento se hará:

– Si se puede compartir widgets.
Se implementará un widget del botón que iniciara el chat que cada cliente colocara donde lo necesite.

– Si la librería tiene dependencias, estas deben cargarse en la principal o se puede obviar.
Se usará un paquete de iconos en la librería.

– Si se puede configurar variables en la librería desde el cliente
Se seteará un parámetro que es global en la librería, para ver como se comporta en el cliente..

Primero implementé como si fuera un proyecto normal para verificar su funcionamiento, separando los componentes que serán reusables.

Repositorio:

https://github.com/JavierSolis/Flutter_DemoLibreria_Libreria

Los cambios para hacerlo librería son:

  • Crear un archivo “lib_chat.dart” donde indican que archivos serán expuestos para los clientes. ( nota: aún no tengo ni he visto un convención para los nombres, por el momento le colocare el prefijo de lib_*)
  • Al momento de usarlo en cliente, no se puede usar las dependencias que se uso en la librería, pero si se exponen, por ejemplo “flutter_icons.dart”, se pueden usar en el cliente.
  • Se creo un nuevo widget “widget_button_chat.dart”, solo para encerrar en una clase el botón del chat y usarlo en el cliente.
library lib_chat;

//expone el wiget button
export 'widget/widget_button_chat.dart';
//expone la página del chat
export 'page/chat_page.dart';
//expone la configuración que usa el chat
export 'constants.dart';

//agregado después para exponer la dependencia que se uso en la librería
export 'package:flutter_icons/flutter_icons.dart';
import 'package:Libreria_chat/page/chat_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';

class ButtonChatWidget extends StatelessWidget {
  final String urlContactPhoto;
  final String nameContact;
  const ButtonChatWidget({Key key, this.nameContact, this.urlContactPhoto})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
      onPressed: () {
        Navigator.pushReplacement(
            context,
            MaterialPageRoute(
                builder: (BuildContext context) => ChatPage(
                    contactName: this.nameContact,
                    urlContactPhoto: this.urlContactPhoto)));
      },
      child: Icon(AntDesign.message1),
    );
  }
}
  • En pubspec.yaml no es necesario ningún cambio, pero para poder identificarlo mejor, cambie el nombre a “libreria_chat“, eso conllevo cambiar el paquete en algunos archivos.
name: Libreria_chat
description: Libreria de chat
...
import 'package:Libreria_chat/constants.dart';
import 'package:Libreria_chat/widget/widget_chat.dart';
import 'package:flutter/material.dart';

class ChatPage extends StatelessWidget {

Repositorio:

https://github.com/JavierSolis/Flutter_DemoLibreria_Libreria_refactorizado

Cliente 1

Para usar la librería en el Cliente 1, se agrega la dependencia en pubspec.yaml. indicando el nombre “Libreria_chat” y la ruta “path:

...
dependencies:
  flutter:
    sdk: flutter
  Libreria_chat:
    path: ../LibreriaRefactorizado #ruta a la librería

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.0
...

En main.dart , agregue el botón button_chat_widget y un icono de una dependencia de la librería Icon(AntDesign.message1) ( esto se pudo después de exponerlo en la librería por defecto sus dependencias no están disponibles) y se configuro la variable constante en la librería CHAT_USER_NAME.

import 'package:Libreria_chat/constants.dart';
import 'package:Libreria_chat/widget/widget_button_chat.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Cliente 1'),
    );
  }
}

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

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    CHAT_USER_NAME = "Javier Solis";
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Icon(AntDesign.message1),
              Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '$_counter',
                style: Theme.of(context).textTheme.headline4,
              ),
            ],
          ),
        ),
        floatingActionButton: ButtonChatWidget(
          urlContactPhoto:
              "https://crop-circle.imageonline.co/images/picture.png",
          nameContact: "Raul",
        ));
  }
}

Video:

Repositorio:

https://github.com/JavierSolis/Flutter_DemoLibreria_Cliente_1

y listo.


Tenemos una librería que podemos rehusar. Ahora podemos tener una librerías de utilitarios que podemos usar en todas nuestras app ( notificaciones, login, control de permisos , etc) que ahorrara tiempo en configurar, en grupo de apps conductor/cliente, etc.

Notas adicionales:

  • Si tengo abierto la librería y hago un cambio, luego haces hotreload en el cliente, los cambios en la librería se cargarán.
  • No implemente el cliente 2, porque los pasos son los mismos al cliente 1.
  • La librería también se puede publicar en pub.dev o referenciar desde github.

Referencias:

Iconos de ejemplo
https://pub.dev/packages/flutter_icons

Lista
https://googleflutter.com/flutter-add-item-to-listview-dynamically/

Border rounded
https://stackoverflow.com/a/57778500

Parte 4 – Configurar Proyecto Flutter para escuchar las notificaciones

Este post es parte del tutorial Flutter agregar push notificaciones para IOS y Android

En main importar el paquete

import 'package:firebase_messaging/firebase_messaging.dart';

En _MyHomePageState , agregar una variable de firebase messaging y configurar sus listener.

...
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
  
  @override
  void initState() {
    super.initState();
    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
      },
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
      },
    );
    _firebaseMessaging.requestNotificationPermissions(
        const IosNotificationSettings(
            sound: true, badge: true, alert: true, provisional: true));
    _firebaseMessaging.onIosSettingsRegistered
        .listen((IosNotificationSettings settings) {
      print("Settings registered: $settings");
    });
    _firebaseMessaging.getToken().then((String token) {
      assert(token != null);
      print("Token: $token");
    });
  }
...

Lanzar el emulador IOS, en caso no sepa como hacerlo, en los siguientes link se describe como:

.

.

Corriendo debera notar que imprime un token

Con el token podemos dirigir la notificación para este dispositivo, esto es opcional ya que sino lo especificamos enviara a todos, pero lo haremos así para poder probar mas rápido porque las notificaciones pueden demorar hasta 1 semana según la documentación.

Vamos a firebase > Cloud Messaging > send your first message

Luego llenamos el formulario y click en “Enviar mensaje de prueba”

Pegamos el token en la ventana luego click en boton “+” y click en “probar”

Revisando el output en visual studio code, se vera la notificación

flutter: onMessage: {from: 1064278709680, collapse_key: com.example.demoNotifications, notification: {body: Contenido de prueba, title: Prueba, e: 1, tag: campaign_collapse_key_5758946879053100963}}

Parte 3 – Creamos proyecto en Firebase

Este post es parte del tutorial Flutter agregar push notificaciones para IOS y Android

Creamos proyecto en firebase desde https://console.firebase.google.com/ y luego click en “Agregar proyecto

En este caso lo nombraremos demo-notifications-flutter

seguir los siguientes pasos, continue hasta crear el proyecto,

En el panel que se muestra, escogemos IOS

En el formulario de registro, pedirá el Id del proyecto, para obtenerlo abrir el proyecto en xcode, abrir el archivo Runner.xcworkspace

Seleccionar según la imagen Runner>Runner>General y copiar lo que indica en Bundle identifier

Volvemos al registro de firebase y llenamos los datos, click en “Registrar app

Descargamos el archivo GoogleService-Info.plist

Copiar el archivo según indica, ojo: copiarlo en la carpeta no tendrá efecto, debe copiarse en el proyecto en xcode, click en siguiente

En este paso se agregaría la librería de firebase, pero eso lo hicimos en un paso previo

Luego ejecutar pod install, flutter ya instancio el pod, para eso ubicarse en la carpeta ios desde la terminal y ejecutar pos install

Si todo va bien debería mostrar un mensaje así.

SI Xcode muestra una advertencia puede cerrarlo, será necesario abrirlo luego.

Ignoraremos el siguiente paso, ya que estamos en un proyecto flutter, eso lo haremos en el proyecto flutter en el siguiente paso, click en Siguiente

y click en “Ir a consola”.

Parte 2 – Agregar dependencias de Firebase Messaging

Este post es parte del tutorial Flutter agregar push notificaciones para IOS y Android

Abrir el proyecto flutter en Visual studio code

Ahora buscamos los paquetes que necesitaremos en https://pub.dev y buscar firebase messaging

Click en “Installing” y seguir las instrucciones, para esta versión indica, agregar firebase_messaging: ^7.0.3 en el archivo pubspec.yaml las dependencias

...
dependencies:
  flutter:
    sdk: flutter
  firebase_messaging: ^7.0.3
...

Guardar el archivo y Visual Studio comenzará a obtener las dependencias, esperar que termine.

Si todo va bien debe mostrar el siguiente mensaje

Listo.

Flutter agregar push notificaciones para IOS y Android

Nota: Revisar la fecha y las dependencias usadas, ya que por políticas de las plataformas o nuevas versiones de estas librerías las indicaciones pueden variar

Para los que pueden guiarse de la documentación oficial, solo necesitan:

Sino pueden ver paso a paso.

Parte 1 – Creamos un proyecto Flutter

Este post es parte del tutorial Flutter agregar push notificaciones para IOS y Android

Para este ejemplo creo una aplicación por defecto de flutter

flutter create demo_notifications

Ejecutar proyecto Flutter en emulador IOS desde Visual Studio Code – VSCode

Primero abrir el proyecto en XCode, y correrlo, si tiene problemas puede revisar este post, donde se describe como ejecutarlo en un dispositivo real:

Abrir el proyecto en Visual studio Code, luego en la abrir la terminal, por comodidad lo abriré desde visual studio code, pero tiene el mismo efecto si lo abre aparte.

Luego en la termina ejecutar: flutter devices

Si aparece que detecto el emulador puede correrlo directamente, sino continue leyendo, aparece

No devices detected.

Luego ejecutar : Flutter doctor

Es posible que obtenga el mensaje de advertencias para XCode

[!] Xcode – develop for iOS and macOS
✗ Xcode installation is incomplete; a full installation is necessary for iOS development.
Download at: https://developer.apple.com/xcode/download/
Or install Xcode via the App Store.
Once installed, run:
sudo xcode-select –switch /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -runFirstLaunch

Luego, siga las instrucciones , correr los dos comando que indica:

sudo xcode-select –switch /Applications/Xcode.app/Contents/Developer

sudo xcodebuild -runFirstLaunch

Luego correr : flutter doctor

Deberá aparecer con un check, ademas de mostrar los dispositivos conectados:

[✓] Xcode – develop for iOS and macOS (Xcode 11.3.1)

Ahora puede correr el proyecto, y deberá mostrarse.

Para probar puede cambiar un texto y probar el hot reload.