Bienvenida e Introducción

1

¡Renovaremos este curso!

2

Desarrollando en Flutter

3

¿Qué es Flutter?

4

Dart y Flutter

5

Sintaxis de Dart

6

¡Renovaremos este curso!

7

Flutter para desarrolladores Android, iOS y Xamarin.forms

8

Flutter para desarrolladores React Native

9

¿Cómo luce una app construída en Flutter?

10

Primer reto

Creando mi entorno de desarrollo

11

¡Renovaremos este curso!

12

Requerimientos de Hardware y Software

13

Instalando Flutter en Android Studio y Visual Studio Code

14

Composición de un proyecto en Flutter

Interfaces en Flutter

15

¡Renovaremos este curso! Te quedan unos días para concluirlo.

16

Programación Declarativa en Flutter

17

Estructura de un programa en Flutter

18

Hola Mundo en Flutter

19

Widgets básicos

20

Widgets con estado y sin estado

21

Análisis de Interfaces de Usuario en Flutter

22

Definiendo los layouts de nuestra interfaz

23

Segundo reto

Widgets sin estado en Flutter

24

¡Renovaremos este curso! Te quedan unos días para concluirlo.

25

Flutter Widgets: Container, Text, Icon, Row

26

Flutter Widgets: Column

27

Recursos en Flutter: Tipografías y Google Fonts

28

Widget Image

29

Widget Apilando Textos

30

Widgets Decorados

31

Widget Imagen Decorada

32

Widget Listview

33

Widget Button, InkWell

34

Tercer reto

Widgets con estado en Flutter

35

¡Renovaremos este curso! Te quedan unos días para concluirlo.

36

Botones en Flutter

37

Clase StatefulWidget: Cómo se compone

38

Widget Floating Action Button

39

Widgets BottomNavigationBar

40

Generando Navegación en BottomNavigationBar

41

Personalizando nuestro BottomNavigation Bar a Cupertino iOS BottomBar

42

Cuarto reto

Fin del Curso

43

¡Renovaremos este curso!

44

Conclusiones

45

¡Terminamos!

Curso de Flutter

Curso de Flutter

Anahí Salgado Díaz de la Vega

Anahí Salgado Díaz de la Vega

Personalizando nuestro BottomNavigation Bar a Cupertino iOS BottomBar

41/45

Lectura

Una posibilidad que tenemos con Flutter es general Widgets idénticos a los de las plataformas nativas, en este caso para iOS con Cupertino.

...

Regístrate o inicia sesión para leer el resto del contenido.

Aportes 49

Preguntas 3

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Si te muestra el siguiente error:

The body might complete normally, causing ‘null’ to be returned, but the return type is a potentially non-nullable type. Try adding either a return or a throw statement at the end.

Necesitas agregarle al final un default y retornar tu vista por ejemplo Home:

De esta manera quedó mi switch

 switch (index) {
            case 0:
              return CupertinoTabView(
                builder: (BuildContext context) => Home(),
              );
            case 1:
              return CupertinoTabView(
                builder: (BuildContext context) => Search(),
              );
            case 2:
              return CupertinoTabView(
                builder: (BuildContext context) => Profile(),
              );
            default:
              return CupertinoTabView(
                builder: (BuildContext context) => Home(),
              );
          }

Código completo aquí, presentará algunas variaciones

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'home.dart';
import 'search.dart';
import 'profile.dart';

class NavifationBarCupertinoIos extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // ignore: todo
    // TODO: implement build
    return Scaffold(
      bottomNavigationBar: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(items: [
          BottomNavigationBarItem(
              icon: Icon(Icons.home, color: Colors.indigo), label: ""),
          BottomNavigationBarItem(
              icon: Icon(Icons.search, color: Colors.indigo), label: ""),
          BottomNavigationBarItem(
              icon: Icon(Icons.person, color: Colors.indigo), label: ""),
        ]),
        tabBuilder: (BuildContext context, int index) {
          switch (index) {
            case 0:
              return CupertinoTabView(
                builder: (BuildContext context) => Home(),
              );
            case 1:
              return CupertinoTabView(
                builder: (BuildContext context) => Search(),
              );
            case 2:
              return CupertinoTabView(
                builder: (BuildContext context) => Profile(),
              );
            default:
              return CupertinoTabView(
                builder: (BuildContext context) => Home(),
              );
          }
        },
      ),
    );
  }
}
Si quieren poner que los botones con cupertino se vean morados activados y grises cuando no, en el widget CupertinoTabBar hay una propiedad llamada "activeColor" y ahi declaran el color "Colors.indigo" o "Colors.purple" en vez de en Icon()

Aqui les dejo el codigo listo para correr, ya corregi el atributo “title” que se encuentra obsoleta en las versiones mas mas nuevas, solo la cambie por “label”.

class PlatziTripsCupertino extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      bottomNavigationBar: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
            backgroundColor: Color(0x33FFFFFF),
            items: [
              BottomNavigationBarItem(
                  icon: Icon(Icons.home, color: Colors.indigo),
                  label: ""
              ),
              BottomNavigationBarItem(
                  icon: Icon(Icons.search, color: Colors.indigo),
                  label: ""
              ),
              BottomNavigationBarItem(
                  icon: Icon(Icons.person, color: Colors.indigo),
                  label: ""
              ),
            ]
        ),
        tabBuilder: (BuildContext context, int index) {
          switch (index) {
            case 0:
              return CupertinoTabView(
                builder: (BuildContext context) => HomeTrips(),
              );
              break;
            case 1:
              return CupertinoTabView(
                builder: (BuildContext context) => SearchTrips(),
              );
              break;
            case 2:
              return CupertinoTabView(
                builder: (BuildContext context) => ProfileTrips(),
              );
              break;
          }
        },
      ),
    );
  }

}

En mi caso para poder el BottonNavigationBar transparente tuve que agregar backgorundColor:

tabBar: CupertinoTabBar(
          activeColor: Colors.indigo,
          backgroundColor: Colors.transparent,
          items: const [
            BottomNavigationBarItem(
                icon: Icon(
                  Icons.home,
                ),
                label: null),
            BottomNavigationBarItem(
                icon: Icon(
                  Icons.search,
                ),
                label: null),
            BottomNavigationBarItem(
                icon: Icon(
                  Icons.person,
                ),
                label: null)
          ],
        ),

Tengo una duda, si desarrollo para Android y para iOS, como consigo usar las particularidades de uno, al crear la app en ambas versiones.

Yo recomendaría quitar la propiedad Text() si no vamos a colocar nada ahí porque se los iconos se verán pegados al borde del CupertinoTabBar, pero si le ponemos texto se ve muy bonito 😄

Quedo Excelente!

Por que no funciona el SnackBar con la versión de cupertino?

Asi me quedo 😄, gracias a los compañeros por sus aportes, ayudan bastante

 //cambia el color del menuItem seleccionado
 activeIcon: Icon(Icons.home, color: Color(0xCFF584CD1),)
CupertinoTabBar(
          backgroundColor: Colors.white.withAlpha(50),
          items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home, color: Colors.white54),
            activeIcon: Icon(Icons.home, color: Color(0xCFF584CD1),)

          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search, color: Colors.white54),
            activeIcon: Icon(Icons.search, color: Color(0xCFF584CD1),)

          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person, color: Colors.white54),
            activeIcon: Icon(Icons.person, color: Color(0xCFF584CD1),)

          )
        ])

.


.

Estimada AnnCode, recibe un cordial saludo, tengo una duda al implementar Cupertino BottomNavigation no funciona el snackBar, es un issue o estaré omitiendo algo del código?

SnackBar no funciona con Cupertino?

Si se recicla la lista del código anterior

static final List<Widget> navigationWidget = [
    HomeView(),
    SearchView(),
    ProfileView()
  ];

Se puede optimizar el tabBuilder

tabBuilder: (BuildContext context, int index){
            return CupertinoTabView(
              builder: (BuildContext context) => navigationWidget[index]
            );
          }

Listo!. Aunque a mi parecer noto un poco menos el efecto de transparencia en Android. De ahi en fuera lo unico que me dio unos problemas fue la clase donde se implemento Cuppertino ya que por alguna razón el editor te da una advertencia de que no se devuelve un valor, no impide el funcionamiento de la aplicación pero se soluciona agregando el comentario ignore: missing_return .

platzi_trips.dart

class PlatziTrips extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _PlatziTrips();
  }


}

class _PlatziTrips extends State<PlatziTrips>{

 static int indexTap =0;


  final List<Widget> widgetsChildren = [
    HomeTrips(),
    SearchTrips(),
    ProfileTrips()
  ];

  void onTapTapped (int index){
    //Controlando el estado del widget
    setState(() {
      indexTap = index; //Recibe un indice y se lo asigna a indexTap
    });
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      body: PlatziTripsCupertino(),

    );
  }

}

platzi_trips_cupertino.dart

 @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      bottomNavigationBar: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
            items: [
              BottomNavigationBarItem(
                  icon: Icon(Icons.home, color: Colors.indigo),
                  title: Text("")
              ),
              BottomNavigationBarItem(
                  icon: Icon(Icons.search, color: Colors.indigo),
                  title: Text("")
              ),
              BottomNavigationBarItem(
                  icon: Icon(Icons.person, color: Colors.indigo),
                  title: Text("")
              ),
            ]
        ),
        //ignore: missing_return
        tabBuilder: (BuildContext context, int index) {
          switch (index) {
            case 0:
              return CupertinoTabView(
                builder: (BuildContext context) => HomeTrips(),
              );
              break;
            case 1:
              return CupertinoTabView(
                builder: (BuildContext context) => SearchTrips(),
              );
              break;
            case 2:
              return CupertinoTabView(
                builder: (BuildContext context) => ProfileTrips(),
              );
              break;

          }

        },
      ),
    );
  }

Resultado:

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'home_trips.dart';
import 'search_trips.dart';
import 'map_trips.dart';
import 'notification_trips.dart';
import 'profile_trips.dart';

class PlatziTripsCupertino extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      bottomNavigationBar: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
            backgroundColor: Colors.white.withAlpha(50),//Color desvanecido en CupertinoTabScaffold
            items: [
              BottomNavigationBarItem(
                  icon: Icon(Icons.home),
                  title: Text("")
              ),
              BottomNavigationBarItem(
                  icon: Icon(Icons.search),
                  title: Text("")
              ),
              BottomNavigationBarItem(
                  icon: Icon(Icons.place),
                  title: Text("")
              ),
              BottomNavigationBarItem(
                  icon: Icon(Icons.notifications),
                  title: Text("")
              ),
              BottomNavigationBarItem(
                  icon: Icon(Icons.person),
                  title: Text("")
              ),
            ]
        ),

        // ignore: missing_return
        tabBuilder: (BuildContext context, int index) {
          switch (index) {
            case 0:
              return CupertinoTabView(
                builder: (BuildContext context) => HomeTrips(),
              );
              break;
            // ignore: missing_return
            case 1:
              return CupertinoTabView(
                builder: (BuildContext context) => SearchTrips(),
              );
              break;
            case 2:
              return CupertinoTabView(
                builder: (BuildContext context) => MapTrips(),
              );
              break;
            case 3:
              return CupertinoTabView(
                builder: (BuildContext context) => NotificationTrips(),
              );
              break;
            case 4:
              return CupertinoTabView(
                builder: (BuildContext context) => ProfileTrips(),
              );
              break;

          }

        },
      ),
    );
  }

}

He seguido todos los paso para usar el tema de Cupertino pero noto que no toma la transparencia, pero si los estilo y colores de la barra inferior.

Hay forma de que manipulando la propiedad canvasColor se agregue ese mismo color entre blanco y transparente, sin necesidad de importar los packages de cupertino?

¿Eliminaron el repositorio?

import ‘package:flutter/material.dart’;
import ‘package:flutter/cupertino.dart’;
import ‘home_trips.dart’;
import ‘search_trips.dart’;
import ‘profile_trips.dart’;

class TripsCupertino extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
bottomNavigationBar: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
backgroundColor: (Colors.white30),

      items: [
        BottomNavigationBarItem(
          icon: Icon(Icons.home,color: Colors.greenAccent),
          title: Text("")
        ),

        BottomNavigationBarItem(
            icon: Icon(Icons.search,color: Colors.greenAccent),
            title: Text("")
        ),

        BottomNavigationBarItem(
            icon: Icon(Icons.person,color: Colors.greenAccent),
            title: Text("")
        ),
      ],
    ),

// ignore: missing_return
tabBuilder: (BuildContext context, int index) {
  // ignore: missing_return
  switch (index) {
    case 0:
      return CupertinoTabView(
        builder: (BuildContext context) => HomeTrips(),
      );
      break;
    case 1:
      return CupertinoTabView(
        builder: (BuildContext context) => SearchTrips(),
      );
      break;
    case 2:
      return CupertinoTabView(
        builder: (BuildContext context) => ProfileTrips(),
      );
      break;
  }
},


  ),

);

}

}

Tengo una duda, el BottomNavigationBar de Cupertino siempre debe ser un Stateless Widget, es que encontré una diferencia en el comportamiento de ambos, en el bar de Cupertino( statless) cuando hago un cambio en la pantalla si cambio de Tab se mantiene el cambio, en cambio en el caso de el widget de Material(Stateful) si cambio de Tab los cambios que hice en la pantalla se reinician

Si no les aparece un blur en su nav (que por defencto es blanco), agreguen el atributo

//Con blur de en color
backgroundColor: Colors.white30
//Con opacidad en tono
backgroundColor: Colors.white.withAlpha(50)

Para intensificar (o difuminar) su efecto

NO LO ENTIENDO. TAMPOCO SE EXPLICA BIEN.

Se supone que cada vez que cree la app tendré que mirar si está o no seleccionado el modo IOS para cupertino?? Me explico mejor… Si lanzo la app para Android, pues como hasta ahora y punto. Pero si quiero que la app esté para IOS, tendré que comentar el home del main y poner el cupertino??? O los dos a la vez??? Por qué no se explica este punto tan importante… Se supone que Flutter es para dos sistemas, IOS y Android… Se debería mostrar cómo le hacemos para que esté bien en los dos… No de uno en uno por separado. Y si ahora yo quisiera subir esta app a IOS y a Android, qué debería hacer???

Por cierto. los snackBar para IOS, qué??? Cómo se soluciona esto?

Para los que tengan problema con la transparencia de la barra, simplemente se soluciona con esto 😄 :

return Scaffold(
      bottomNavigationBar: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
          backgroundColor: Colors.white.withAlpha(70),
          items: [
            BottomNavigationBarItem(
                icon:Icon(Icons.home, color: Colors.indigo,),
                label: "",
            ),
            BottomNavigationBarItem(
              icon:Icon(Icons.search, color: Colors.indigo,),
              label: "",
            ),
            BottomNavigationBarItem(
              icon:Icon(Icons.person, color: Colors.indigo,),
              label: "",
            ),
          ],```

Bueno en principio me dio algo de error, pero viendo la estructura lo pude identificar y reparar:

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

import 'package:platzi_trips_app/home_trips.dart';
import 'package:platzi_trips_app/profile_trips.dart';
import 'package:platzi_trips_app/search_trips.dart';

class PlatziTripsCupertino extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        bottomNavigationBar: CupertinoTabScaffold(
      tabBar: CupertinoTabBar(items: [
        BottomNavigationBarItem(
            icon: Icon(Icons.home, color: Colors.indigo), title: Text("")),
        BottomNavigationBarItem(
            icon: Icon(Icons.search, color: Colors.indigo), title: Text("")),
        BottomNavigationBarItem(
            icon: Icon(Icons.person, color: Colors.indigo), title: Text("")),
      ]),
      tabBuilder: (BuildContext context, int index) {
        switch (index) {
          case 0:
            return CupertinoTabView(
              builder: (BuildContext context) => HomeTrips(),
            );
            break;
          case 1:
            return CupertinoTabView(
              builder: (BuildContext context) => SearchTrips(),
            );
            break;
          case 2:
            return CupertinoTabView(
              builder: (BuildContext context) => ProfileTrips(),
            );
            break;
        }
      },
    ));
  }
}

mi resultado:

no tengo iphone asi que te creo 😛

switch tambien se puede en android

Hola,
a mi me queda practicamente blanco, alguien podría ayudarme en decirme que podría estar mal.
Gracias

Está caido el link, deben estar pendientes, para algo se paga

¡Contento con el resultado! 😉

No me gustaba la idea de tener que escribir de nuevo el Scaffold de la app, busqué y encontré que se puede preguntar por la plataforma haciendo uso de un enumerador de clase para el tipo TargetPlatform. Hice otras optimizaciones para tratar de evitar la duplicación de código, este es el resultado en 2022:

class _MainView extends State<MainView> {
  int widgetIndex = 0;
  static List<Widget> children = [HomeView(), SearchView(), ProfileView()];

  static const List<Icon> icons = [
    Icon(Icons.home),
    Icon(Icons.search),
    Icon(Icons.person)
  ];

  void barItemTapped(int index) {
    setState(() {
      widgetIndex = index;
    });
  }

  List<BottomNavigationBarItem> barItems = icons
      .map((icon) => BottomNavigationBarItem(icon: icon, label: null))
      .toList();

  Widget bottomNavigationBar() {
    if (defaultTargetPlatform == TargetPlatform.iOS) {
      return CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
          items: barItems,
          activeColor: Colors.purple,
          inactiveColor: Colors.grey.shade400,
          backgroundColor: Colors.white30,
        ),
        tabBuilder: (context, index) =>
            CupertinoTabView(builder: (context) => children[index]),
      );
    } else {
      return BottomNavigationBar(
          onTap: barItemTapped, currentIndex: widgetIndex, items: barItems);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: children[widgetIndex],
        bottomNavigationBar: Theme(
            data: Theme.of(context).copyWith(
                canvasColor: Colors.white, primaryColor: Colors.purple),
            child: bottomNavigationBar()));
  }

Estoy contento con el resultado. Lo único: la descripción se pone un poco más arriba con Cupertino, pero se soluciona dando más espacio en el top (me dio pereza hacerlo 😃)

Recomendaría cambiar el switch:

tabBuilder: (BuildContext context, int index) {
          switch (index) {
            case 0:
              return CupertinoTabView(
                builder: (BuildContext context) => HomeTrips(),
              );
              break;
            case 1:
              return CupertinoTabView(
                builder: (BuildContext context) => SearchTrips(),
              );
              break;
            case 2:
              return CupertinoTabView(
                builder: (BuildContext context) => ProfileTrips(),
              );
              break;
          }

por solamente:

 tabBuilder: (BuildContext context, int index) {
           return  CupertinoTabView(
              builder: (BuildContext context) => 	 
               screenChildren[index],
            );
    },

Funcionan exactamente igual y son muchas menos líneas de codigo

presenta un error en la llave del tapBuilder…
The body might complete normally, causing ‘null’ to be returned, but the return type is a potentially non-nullable type. Try adding either a return or a throw statement at the end.

tabBuilder: (BuildContext context, int index) {

Me encantó como se ve así, creo que usaré esta barra para próximos desarrollos

gracias!

@anncode El código no esta actualizado en github

Genial, me gusta mucho esta posibilidad que ofrece flutter.

Link caido por favor solucionen y actualicen… Gracias

Cuando agregó el CupertinoTabScaffold el margin top del description_place se reduce y el texto inicia bajo la primera imagen del slider. ¿Hay forma de solo activar este Widget si es cargado en iOS?

Sucede que cuando cambio entre vistas rápidamente el emulador me saca de la app.
¿Alguien más con este problema?

Sí me funcionó

en el ejemplo anterio

tabBuilder: (BuildContext context, int index) {
          switch (index) {
            case 0:
              return CupertinoTabView(
                builder: (BuildContext context) => HomeTrips(),
              );
              break;
            case 1:
              return CupertinoTabView(
                builder: (BuildContext context) => SearchTrips(),
              );
              break;
            case 2:
              return CupertinoTabView(
                builder: (BuildContext context) => ProfileTrips(),
              );
              break;

          }
},

a

return CupertinoTabView(
              builder: (BuildContext context) => widgetChlidren[index],
            );
final List<Widget> widgetChlidren = [
    Home(),
    SearchTrips(),
    ProfileTrips(),
  ];

Wow. Todo el tiempo y codigo que ahorra Flutter.

No me toma la transparencia y no se porque me cambia el margin top del titulo de la pagina, esta raro 🤔
Menu normal:

con cupertino:

Alguien sabe porque??

    return Scaffold(
      bottomNavigationBar: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
          backgroundColor: Colors.black26,
          inactiveColor: Colors.white,
          activeColor: Colors.lime,
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.home_filled),
              label: null
            ),

            BottomNavigationBarItem(
              icon: Icon(Icons.search_off),
              label: null,
            ),

            BottomNavigationBarItem(
              icon: Icon(Icons.person_pin_rounded),
              label: null,
            ),
          ],
        ),

        tabBuilder: (BuildContext context, int index) {

          switch(index) {

            case 0: return CupertinoTabView(
              builder: (BuildContext context) => HomeTrips(),
            ); break;

            case 1: return CupertinoTabView(
              builder: (BuildContext context) => SearchTrips(),
            ); break;

            case 2: return CupertinoTabView(
              builder: (BuildContext context) => PorfileTrips(),
            ); break;
          }

          return null;
        }
      ),
    );