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 50

Preguntas 3

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Si te muestra el siguiente error:

The body might complete normally, causing 鈥榥ull鈥 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 鈥渢itle鈥 que se encuentra obsoleta en las versiones mas mas nuevas, solo la cambie por 鈥渓abel鈥.

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)
          ],
        ),

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 馃槃

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

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 鈥榩ackage:flutter/material.dart鈥;
import 鈥榩ackage:flutter/cupertino.dart鈥;
import 鈥榟ome_trips.dart鈥;
import 鈥榮earch_trips.dart鈥;
import 鈥榩rofile_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

Hola que tal, intente ingresar al recurso pero ya no se encuentra disponible 馃槮

https://github.com/anncode1/Curso-de-Flutter-en-Platzi/tree/16.BottomNavigationBarCupertino/platzi_trips_app/lib

隆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 鈥榥ull鈥 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;
        }
      ),
    );