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

Tercer reto

34/45

Lectura

  • Aprovecha las clase Widget Listview para crear tu propia lista personalizada.
  • Realiza una interfaz como se ve en la figura. Puedes utilizar iconos, e imágenes para las fotografías.
  • Créala basada en esta interfaz pero totalmente a tu gusto.
  • Compártenos tus resultados en la sección de discusiones.
Captura de pantalla 2018-12-28 a la(s) 13.07.52.png

...

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

Aportes 214

Preguntas 3

Ordenar por:

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

Reto:
Github

!! Reto cumplido !!
GitHub: https://github.com/BrayanMamani/Designers

El reto

Intente hacer algo diferente, aun que el codigo quedo algo desordenado.

https://github.com/AoTanuki/bestiaryApp

Por fin pude terminar 😄
Código

Tardé porque no comprendía lo del CustomClipper, pero hice esto:

Y el código lo realicé así.

CustomAppBar:


class CustomAppBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    final iconAppBar = Container(
      height: 90,
      padding: EdgeInsets.only(
        top: 43,
        left: 20.0
      ),
      child: InkWell(
        child: Column(
          verticalDirection: VerticalDirection.down,
          children: <Widget>[
            Icon(
              Icons.menu,
              color: Colors.white
            )
          ],
        ),
      )
    );// iconAppBar Container

    final titleBar = Container(
      margin: EdgeInsets.only(
        top: 40.0
      ),
      alignment: Alignment.center,
      child: Text(
        "Video Games",
        style: TextStyle(
          color: Colors.white,
          fontSize: 26.0,
          fontWeight: FontWeight.bold,
        ),
      ),
    );// titleBar Container

    var imageBar = Container(
      height: 150,
      decoration: BoxDecoration(
        image: DecorationImage(
            fit: BoxFit.cover,
            image: AssetImage("assets/img/joystick.jpg")
        )
      ),
    );

    return Stack(
      children: <Widget>[
        imageBar,
        iconAppBar,
        titleBar,
      ],
    );
  }
}

class MyClipper extends CustomClipper<Path>{
  @override
  Path getClip(Size size) {
    Path path = Path();
    path.lineTo(0.0, size.height - 40.0);

    var firstControlPoint = new Offset(size.width / 6, size.height - 50);

    var firstEndPoint = new Offset(size.width / 3, size.height - 30.0);
    path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy,
        firstEndPoint.dx, firstEndPoint.dy);

    var secondControlPoint = new Offset( size.width * 0.51, size.height);

    var secondEndPoint = new Offset(size.width * (4 / 6), size.height - 30);
    path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy,
        secondEndPoint.dx, secondEndPoint.dy);

    var thirdControlPoint = new Offset(size.width * (5 / 6), size.height - 60);

    var thirdEndPoint = new Offset(size.width, size.height - 40.0);
    path.quadraticBezierTo(thirdControlPoint.dx, thirdControlPoint.dy,
        thirdEndPoint.dx, thirdEndPoint.dy);

    path.lineTo(size.width, size.height - 40.0);
    path.lineTo(size.width, 0.0);
    path.close();

    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return false;
  }

}

videogame_card:


class VideoGamesCard extends StatelessWidget {
  String name = "Uncharted";
  String pathImage = "assets/img/uncharted.jpg";
  String platform = "PS3/PS4";

  VideoGamesCard(this.name, this.platform, this.pathImage);

  @override
  Widget build(BuildContext context) {

    final gamePhoto = Container(
      margin: EdgeInsets.only(
        right: 20.0
      ),
      height: 40.0,
      width: 40.0,
      decoration: BoxDecoration(
          shape: BoxShape.circle,
          color: Colors.blue,
          image: DecorationImage(
              fit: BoxFit.cover,
              image: AssetImage("assets/img/control.png")
          )
      ),
    ); // gamePhoto Container

    final platformName = Container(
      child: Text(
        "Plataforma: $platform",
        style: TextStyle(
          color: Colors.cyan,
          fontSize: 14.0,
          fontWeight: FontWeight.normal,
        )
      ),
    );// platformName

    final videoGameName = Container(
      child: Text(
        name,
        style: TextStyle(
          color: Colors.black,
          fontSize: 16.0,
          fontWeight: FontWeight.w900
        )
      ),
    ); // videoGameName Container

    final videoGamePhoto = Container(
      margin: EdgeInsets.only(
        top: 10.0,
        left: 15.0,
        right: 10.0
      ),
      height: 80.0,
      width: 80.0,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        image: DecorationImage(
          fit: BoxFit.cover,
          image: AssetImage(pathImage)
        )
      ),
    ); // videoGamePhoto Container

    final dataGame = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        videoGameName,
        platformName
      ],
    ); //dataName Column

    return Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        videoGamePhoto,
        Expanded(
          child: dataGame
        ),
        gamePhoto
      ],
    );
  }
}

videogame_card_list:

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

class VideoGamesCardList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        VideoGamesCard("Uncharted: Drake's Treasure", "PS3/PS4", "assets/img/uncharted_drakes_fortune.jpg"),
        VideoGamesCard("Gears of War 4", "Xbox One/PC", "assets/img/gow4.jpg"),
        VideoGamesCard("Super Mario Oddysey", "Nintendo Switch", "assets/img/odyssey.jpg"),
        VideoGamesCard("God of War", "PS4", "assets/img/boy.jpg"),
        VideoGamesCard("Cuphead", "Xbox One/PC/\nNintendo Switch/macOS/Tesla", "assets/img/cuphead.jpg"),
      ],
    );
  }
}

Y en main:

import 'package:flutter/material.dart';
import 'custom_appbar.dart';
import 'videogames_card_list.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold (
          body: Column(
            children: <Widget>[
              ClipPath(
                clipper: MyClipper(),
                child: CustomAppBar()
              ),
              VideoGamesCardList()
            ],
          )
      )
    );
  }
}

Reto Cumplido

Aqui esta el resultado del reto, la curva la hice a código con el widget ClipPath. Les dejo el código (la clase se llama GradientBack porque al principio creí que con una degradación podía hacer la curva, pero así no era, y luego no lo cambie XD ):

import 'package:flutter/material.dart';

class GradientBack extends StatelessWidget{



  @override
  Widget build(BuildContext context) {

    final title = Container(
      margin: EdgeInsets.only(
        top: 40.0,
        left: 100.0,
      ),
      child: Text(
        "DESIGNERS",
        style: TextStyle(
          fontSize: 20.0,
          fontWeight: FontWeight.bold,
          color: Colors.white,
        ),
      ),
    );

    final menuIco = Container(
      margin: EdgeInsets.only(
          top: 40.0,
          left: 20.0,
      ),

      child: Icon(
        Icons.menu,
        color: Colors.white,
      ),

    );

    final gradient = Container(
      height: 120.0,
      alignment: Alignment(-0.9, -0.6),

      decoration: BoxDecoration(
        color: Colors.blueAccent,
        image: DecorationImage(
          image: AssetImage("assets/img/office.png"),
          fit: BoxFit.cover,
          colorFilter: ColorFilter.mode(Colors.blueAccent.withOpacity(0.3), BlendMode.dstATop),
        )
      ),
        child: Row(
          children: <Widget>[
            menuIco,
            title,
          ],
        ),

    );

    //return gradient;
    return ClipPath(
      child: gradient,
      clipper: AppBarWaveClipper(),
    );
  }

}

class AppBarWaveClipper extends CustomClipper<Path>{
  @override
  Path getClip(Size size) {

    var path = Path();
    var oneFraction = size.width/6;

    var firstControlPoint = new Offset(oneFraction, size.height - 35);
    var firstEndPoint = new Offset(oneFraction * 2, size.height - 20);

    var secondControlPoint = new Offset(oneFraction * 3, size.height);
    var secondEndPoint = new Offset(oneFraction * 4, size.height - 20);

    var thirdControlPoint = new Offset(oneFraction * 5, size.height - 35);
    var thirdEndPoint = new Offset(oneFraction * 6, size.height - 30);

    path.lineTo(0.0, size.height - 30);

    path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy, firstEndPoint.dx, firstEndPoint.dy);

    path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy, secondEndPoint.dx, secondEndPoint.dy);

    path.quadraticBezierTo(thirdControlPoint.dx, thirdControlPoint.dy, thirdEndPoint.dx, thirdEndPoint.dy);

    path.lineTo(size.width, 0.0);

    path.close();
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    // TODO: implement shouldReclip
    return false;
  }

Así quedo el mío, aunque me aleje un poco del diseño original:

Si lo quieren probar, aquí les dejo el código.

Reto: mi lista simula la vista del historial de una app que seria una pokedex y mostraria todos los pokemones que se escanearon: :3

las imagenes que prepare en el diseño eran para una pantalla mas pequeña y por eso me quedo de esa manera lol.

asi la prepare con el curso que lleve de Figma aqui en platzi :3:

Esto es lo que hice para el reto!, pero no pude eso si darle la misma forma pero pude dejarlo así 😃
 
 

 
 
Tambien le agrege este efecto cuando se da tap en el email :3
 

Ocupé de plantilla la imagen que pusieron en el ejercicio, les comparto mi resultado.

![](

class WaveHeader extends StatelessWidget {
  String title = "Developers";
  Wave3Header(this.title);

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Container(
          height: double.infinity,
          width: double.infinity,
          child: CustomPaint(
            painter: _WaveHeaderPainter(),
          ),
        ),
        Container(
          alignment: Alignment(-0.825, -0.825),
          child: Text(
            title,
            style: TextStyle(
                color: Colors.white,
                fontSize: 30.0,
                fontFamily: "Lato",
                fontWeight: FontWeight.bold),
          ),
        ),
      ],
    );
  }
}

class _WaveHeaderPainter extends CustomPainter {
  final quarter = 1 / 4;
  final eighth = 1 / 8;

  @override
  void paint(Canvas canvas, Size size) {
    final colors = LinearGradient(
      colors: [
        Color(0xFF512DA8),
        Color(0xFF303F9F),
        Color(0xFF3F51B5),
        Color(0xFF00BCD4),
      ],
      begin: FractionalOffset(0.3, 0.0),
      end: FractionalOffset(0.6, 0.25),
    );

    var rect = Offset.zero & size;
    final paint = Paint()
      ..style = PaintingStyle.fill
      ..shader = colors.createShader(rect);
    //..color = Color.fromRGBO(88, 76, 209, 1.0);
    //paint.strokeWidth = 10.0;

    final path = Path();

    path.lineTo(0, size.height * 0.2);
    path.quadraticBezierTo(size.width * (eighth), size.height * 0.15,
        size.width * quarter, size.height * 0.2);
    path.quadraticBezierTo(size.width * (eighth * 3), size.height * 0.25,
        size.width * (quarter * 2), size.height * 0.2);
    path.quadraticBezierTo(size.width * (eighth * 5), size.height * 0.15,
        size.width * (quarter * 3), size.height * 0.2);
    path.quadraticBezierTo(size.width * (eighth * 7), size.height * 0.25,
        size.width, size.height * 0.2);
    path.lineTo(size.width, 0);

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

Excelente experiencia, desesperé un poco al principio, pero poco a poco le fui agarrando el gustito

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

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

class GuilleApp extends StatelessWidget{

  final String url="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcS80VJR4jJXEOrDUBV1_vHMord7JrtwL3xwMOrBffPMvPoduDR3&usqp=CAU";
  //////////////////////////////////////////////////////////////
  @override
  Widget build(BuildContext context) {
   return MaterialApp(
     home: Scaffold(

    body: Stack(
      children: [
        CardList(),

        ClipPath(
          clipper: MyClipper(),
          child: Container(
            decoration: BoxDecoration(
              color: Colors.deepPurple,
              image: DecorationImage(
                  image: NetworkImage(url),
              fit: BoxFit.cover,
                colorFilter: ColorFilter.mode(Colors.deepPurple.withOpacity(0.5),BlendMode.darken)
              )
            ),

            height: 150,
            child: Center(
              child: Text("Acreedores",
              style: TextStyle(
                fontSize: 22,
                fontWeight: FontWeight.bold,
                  color: Colors.white
              ),),
            ),
          ),
        )



      ],

    ),
    )
   );
  }
}

class MyClipper extends CustomClipper<Path>{
  @override
  Path getClip(Size size) {
    Path path=Path();
    path.lineTo(0.0, size.height-40.0);
    var firstControlPoint = new Offset(size.width/6, size.height-60);
    var firstEndPoint = new Offset(size.width/3, size.height-30.0);
    path.quadraticBezierTo(firstControlPoint.dx,firstControlPoint.dy,
        firstEndPoint.dx,firstEndPoint.dy);
    var secondControlPoint = new Offset( size.width*0.5,size.height);
    var secondEndPoint = new Offset(size.width*(4/6),size.height-30);
    path.quadraticBezierTo(secondControlPoint.dx,secondControlPoint.dy,
        secondEndPoint.dx,secondEndPoint.dy);
    var thirdControlPoint = new Offset(size.width*(5/6),size.height-60 );
    var thirdEndPoint = new Offset(size.width, size.height-40.0);
    path.quadraticBezierTo(thirdControlPoint.dx,thirdControlPoint.dy,
        thirdEndPoint.dx,thirdEndPoint.dy);
    path.lineTo(size.width, size.height-40.0);
    path.lineTo(size.width, 0.0);
    path.close();

    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
   return false;
  }

}

class Card extends StatelessWidget{

  String urlPhoto;
  String mensaje;
  String nombre;
  bool leido;


  Card(this.urlPhoto,this.nombre, this.mensaje, this.leido);

  @override
  Widget build(BuildContext context) {
   return Row(
     children: [
       Container(
         margin: EdgeInsets.only(
             top: 20,
             left: 10
         ),
         width:  60,
         height: 60,
         decoration: BoxDecoration(
             shape: BoxShape.circle,
             image: DecorationImage(
                 fit: BoxFit.cover,
                 image: AssetImage(urlPhoto)
             )
         ),
       ),

       Container(
         width: 220,
         margin: EdgeInsets.only(
           top: 10,
           left: 20,

         ),

         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,



           children: [

             Text(nombre,
                 textAlign: TextAlign.left,
                 style: TextStyle(
                   fontSize: 15,
                   fontWeight: FontWeight.bold,
                   color: Colors.black54,





                 ),
             ),



             Text(mensaje,
             textAlign: TextAlign.left,
             style: TextStyle(
               fontSize: 12,
               fontStyle: FontStyle.italic,
                 color: Colors.black38
             ),)





           ],
         ),
       ),
       Container(
    margin: EdgeInsets.only(left: 10),
    height: 40.0,
    width: 40.0,
    decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(40),
    color:  Colors.red
    ),
    child: Icon(

     Icons.mail ,
    color: Colors.white,
    size: 20.0,
       )
       )

     ],


   );
  }

}

class CardList extends StatelessWidget{
  @override
  Widget build(BuildContext context) {

    return Container(
      margin: EdgeInsets.only(top: 100),
      child: ListView(
          scrollDirection: Axis.vertical,
        children: [
          Card("assets/image/jhon.jpeg","Jhon Wick","Voy pormi dinero, llevo un lápiz",true),
          Card("assets/image/vito.jpeg","Don Vito Corleone","Págame, seamos razonables",true),
          Card("assets/image/busqueda.jpeg","Bryan Mills","te buscaré, te encontraré y te mataré",true),
          Card("assets/image/chuck.jpeg","Chuck Norris","Déjate de juegos niño",true),
          Card("assets/image/pablo.jpeg","Pablo Escobar","Mataré a tu madre, tu hermana tu...",true),
          Card("assets/image/arnold.jpeg","Jhon Matrix","Vietnam parecerá un juego....",true),
          Card("assets/image/yoda.jpg","Yoda","Pagarme tu debes",true),

        ],
      ),
    );
  }

}

Resultado

main.dart

import 'package:flutter/material.dart';
import 'package:reto_2/reto.dart';

void main() => runApp(
  MaterialApp(
    debugShowCheckedModeBanner: false,
    home: Reto(),
  )
);

reto.dart

import 'package:flutter/material.dart';
import 'package:reto_2/contact_card.dart';
import 'package:reto_2/custom_app_bar.dart';

class Reto extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CustomAppBar(
        title: Text(
          "DESIGNERS",
          style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 20,
            color: Colors.white
          ),
        ),
        navigatorButton: IconButton(
          icon: Icon(
            Icons.menu, 
            color: Colors.white
          ), 
          onPressed: null
        ),
        centerTitle: true,
      ),
      body: Stack(
        children: <Widget>[
          ListView(
            children: <Widget>[
              ContactCard("Juan Manuel", 7, "assets/profile_1.jpg", enable: false),
              Divider(),
              ContactCard("Nuria Sofia", 5, "assets/profile_2.jpeg"),
              Divider(),
              ContactCard("Oscar Tito", 10, "assets/profile_3.jpg"),
              Divider(),
              ContactCard("Roberto Julian", 4, "assets/profile_4.jpeg"),
              Divider(),
              ContactCard("Maria Alexandra", 15, "assets/profile_5.jpeg"),
            ],
          )
        ],
      ),
    );
  }
}

custom_app_bar.dart

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

class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
  final Widget title;
  final bool centerTitle;
  final Widget navigatorButton;

  CustomAppBar({this.title, this.centerTitle = false, this.navigatorButton});

  @override
  State<StatefulWidget> createState() => _CustomAppBarState();

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight + 32);
}

class _CustomAppBarState extends State<CustomAppBar> {
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(bottom: 0),
      child: Stack(
        children: <Widget>[
          Material(
            elevation: 1,
            color: Colors.yellow,
            shape: AppBarShape(),
            clipBehavior: Clip.antiAliasWithSaveLayer,
            child: Container(
              height: widget.preferredSize.height + 20,
              decoration: BoxDecoration(
                  image: DecorationImage(
                      image: AssetImage("assets/place.jpg"),
                      fit: BoxFit.cover,
                      colorFilter: ColorFilter.mode(
                          Color.fromRGBO(65, 130, 184, 0.85), 
                          BlendMode.srcATop
                      )
                  )
              ),
            ),
            
          ),
          _getAppBar()
        ],
      ),
    );
  }

  Widget _getAppBar() {
    return Container(
      margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
      height: kToolbarHeight,
      width: double.maxFinite,
      child: Stack(
        children: _getList(),
      ),
    );
  }

  Widget _getTitle() {
    Widget wTitle = widget.title != null ? widget.title : Container();
    return widget.centerTitle
        ? Center(child: wTitle)
        : Container(padding: EdgeInsets.only(left: 50), child: wTitle);
  }

  List<Widget> _getList() {
    List<Widget> list = List();
    list.add(_getTitle());
    if (widget.navigatorButton != null) {
      list.add(widget.navigatorButton);
    }
    return list;
  }
}

app_bar_shape.dart

import 'package:flutter/material.dart';

class AppBarShape extends ContinuousRectangleBorder {
  @override
  Path getOuterPath(Rect rect, {TextDirection textDirection}) {
    Path path = Path();

    double curveSize = 30;
    double heigth = rect.height - curveSize;
    double block = rect.width / 8;

    path.lineTo(0, heigth);
    path.lineTo(block, heigth + 0.03 * curveSize);
    var controlPoint = Offset(block + block * 0.5, heigth + 0.03 * curveSize);
    var endPoint = Offset(block * 2 + 0.2 * block, heigth + 0.2 * curveSize);
    path.quadraticBezierTo(
        controlPoint.dx, controlPoint.dy, endPoint.dx, endPoint.dy);

    controlPoint = Offset(block * 4, heigth + curveSize);
    endPoint = Offset(block * 6, heigth + 0.2 * curveSize);
    path.quadraticBezierTo(
        controlPoint.dx, controlPoint.dy, endPoint.dx, endPoint.dy);

    controlPoint = Offset(block * 6 + 0.5 * block, heigth + 0.03 * curveSize);
    endPoint = Offset(block * 7, heigth + 0.03 * curveSize);
    path.quadraticBezierTo(
        controlPoint.dx, controlPoint.dy, endPoint.dx, endPoint.dy);

    path.lineTo(block * 8, heigth);
    path.lineTo(block * 8, 0);
    path.close();
    return path;
  }
}

contact_card.dart

import 'package:flutter/material.dart';

class ContactCard extends StatelessWidget {

  final String name;
  final int experience;
  final String pathImage;
  final bool enable;

  ContactCard(this.name, this.experience, this.pathImage, {this.enable = true});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(12),
      child: Row(
        children: <Widget>[
          Container(
            height: 50,
            width: 50,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              image: DecorationImage(
                image: AssetImage(pathImage),
                fit: BoxFit.cover
              )
            ),
          ),
          Container(width: 12),
          Flexible(
            fit: FlexFit.tight,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(
                  name,
                  style: TextStyle(
                    fontWeight: FontWeight.bold
                  ),
                ),
                Container(height: 8.0),
                Text("Experience: ${experience < 10 ? "0" : ""}$experience years")
              ],
            ),
          ),
          Container(
            height: 40,
            width: 40,
            child: Center(
              child: Icon(
                Icons.mail,
                color: enable ? Colors.white : Colors.black45
              ),
            ),
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: enable ? Colors.red : Colors.grey.withOpacity(0.5)
            ),
          )
        ],
      ),
    );
  }
}

Me costo bastante la verdad pero lo logre 😅😎


Mi Solución:

list_item.dart

import 'package:flutter/material.dart';

class ListItem extends StatelessWidget{
  String profileImage = "";
  String profileName  = "";
  String profileResume = "";
  bool   redMail = true;

  ListItem(this.profileImage, this.profileName, this.profileResume, this.redMail);

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    final photo = Container(
      width: 60.0,
      height: 60.0,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        image: DecorationImage(
          fit: BoxFit.cover,
          image: AssetImage(profileImage)
        )
      ),
    );

    final profileInfo = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Text(
          profileName,
          textAlign: TextAlign.left,
          style: TextStyle(
            fontWeight: FontWeight.w900,
            fontSize: 18.0,
            color: Colors.black54
          ),

        ),
        Text(
          profileResume,
          style: TextStyle(
            color: Colors.grey,
            fontSize: 14.0
          ),
          textAlign: TextAlign.left,
        )
      ],
    );

    final mailIcon = Container(
      width: 40.0,
      height: 40.0,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: redMail ? Colors.red : Color(0xFFCCCCCC),
      ),
      child: Icon(
        Icons.mail,
        color: redMail ? Colors.white : Colors.black38,
        size: 20.0,
      ),
    );


    return
      Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          ListTile(
            leading: photo,
            title: Text(
              profileName,
              textAlign: TextAlign.left,
              style: TextStyle(
                  fontWeight: FontWeight.w900,
                  fontSize: 18.0,
                  color: Colors.black54
              ),
            ),
            subtitle: Text(
              profileResume,
              style: TextStyle(
                  color: Colors.grey,
                  fontSize: 14.0
              ),
              textAlign: TextAlign.left,
            ),
            trailing: mailIcon
          ),
          Divider(
            color: Colors.grey,
          )
        ],
      );
  }
}

main.dart

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

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Reto 3',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          leading: Icon(
            Icons.menu,
            color: Colors.white,
          ),
          title: Text(
            "DESIGNERS",
            style: TextStyle(
              color: Colors.white,
              fontWeight: FontWeight.bold
            ),
          ),
        ),
        body: ListView(
          children: <Widget>[
            ListItem("assets/img/profile01.jpg", "Amanda Murphy", "Experience: 04 years", false),
            ListItem("assets/img/profile02.jpg", "Grace Hartzel", "Experience: 15 years", true),
            ListItem("assets/img/profile03.jpg", "Bella Hadid", "Experience: 10 years", true),
            ListItem("assets/img/profile04.jpg", "Julia Bergshoeff", "Experience: 07 years", true),
            ListItem("assets/img/profile05.jpeg", "Malayka Firth", "Experience: 05 years", true),
          ],
        ),
      )
    );
  }
}

pubspec.yaml

name: reto3
description: Reto 3 Flutter

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

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

dev_dependencies:
  flutter_test:
    sdk: flutter


# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec

# The following section is specific to Flutter.
flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  assets:
    - assets/img/
  # To add assets to your application, add an assets section, like this:
  # assets:
  #  - images/a_dot_burr.jpeg
  #  - images/a_dot_ham.jpeg

  # An image asset can refer to one or more resolution-specific "variants", see
  # https://flutter.dev/assets-and-images/#resolution-aware.

  # For details regarding adding assets from package dependencies, see
  # https://flutter.dev/assets-and-images/#from-packages

  # To add custom fonts to your application, add a fonts section here,
  # in this "flutter" section. Each entry in this list should have a
  # "family" key with the font family name, and a "fonts" key with a
  # list giving the asset and other descriptors for the font. For
  # example:
  # fonts:
  #   - family: Schyler
  #     fonts:
  #       - asset: fonts/Schyler-Regular.ttf
  #       - asset: fonts/Schyler-Italic.ttf
  #         style: italic
  #   - family: Trajan Pro
  #     fonts:
  #       - asset: fonts/TrajanPro.ttf
  #       - asset: fonts/TrajanPro_Bold.ttf
  #         weight: 700
  #
  # For details regarding fonts from package dependencies,
  # see https://flutter.dev/custom-fonts/#from-packages

Mi Resultado:

Reto:

¡Reto cumplido!

import 'package:flutter/material.dart';

class CustomAppBar extends StatelessWidget {

  String title;

  CustomAppBar(this.title);

  @override
  Widget build(BuildContext context) {

    final iconAppbar = Container(
      height: 80.0,
      padding: EdgeInsets.only(
        top: 38.0,
        left: 20.0
      ),
      child: InkWell(
        child: Column(
          verticalDirection: VerticalDirection.down,
          children: <Widget>[
            Icon(
              Icons.menu,
              color: Colors.white,
            )
          ],
        ),
      ),
    );

    final designAppbar = Container(
      height: 80.0,
      padding: EdgeInsets.only(
        top: 24.0,
        right: 10.0
      ),
      child: Center(
        child: Text(
          title,
          style: TextStyle(
            color: Colors.white,
            fontSize: 20.0,
            fontWeight: FontWeight.w500
          ),
        ),
      ),
    );

    final imageAppbar = Container(
      height: 86.0,
      decoration: BoxDecoration(
        image: DecorationImage(
          image: AssetImage("images/custom_appbar.png"),
          fit: BoxFit.fill
        )
      ),
    );

    return Stack(
      children: <Widget>[
        imageAppbar,
        designAppbar,
        iconAppbar,
      ],
    );
  }
}```

**Reto terminadou! ᕙ(`▿´)ᕗ **
Este fue mi resultado:

main.dart

import 'package:flutter/material.dart';
import 'cabeceraDiseno.dart';
import 'review_list.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body:  Stack(
          children:<Widget>[
            ListView(
              children:<Widget>[
                CabeceraDiseno(),
                ReviewList(),
              ],
            ),
          ],
        ),
        //ReviewList(),
        //CabeceraDiseno(),
      ),
    );
  }
}

cabecera.dart:

import 'package:flutter/material.dart';

class Cabecera extends CustomClipper<Path>{
  @override
  Path getClip(Size size) {
    // TODO: implement getClip

    var path= Path();
    path.lineTo(0.0, size.height-40.0);
    var firstControlPoint = new Offset(size.width/6, size.height-60);
    var firstEndPoint = new Offset(size.width/3, size.height-30.0);
    path.quadraticBezierTo(firstControlPoint.dx,firstControlPoint.dy, 
    firstEndPoint.dx,firstEndPoint.dy);
    var secondControlPoint = new Offset( size.width*0.5,size.height);
    var secondEndPoint = new Offset(size.width*(4/6),size.height-30);
    path.quadraticBezierTo(secondControlPoint.dx,secondControlPoint.dy, 
    secondEndPoint.dx,secondEndPoint.dy);
    var thirdControlPoint = new Offset(size.width*(5/6),size.height-60 );
    var thirdEndPoint = new Offset(size.width, size.height-40.0);
    path.quadraticBezierTo(thirdControlPoint.dx,thirdControlPoint.dy, 
    thirdEndPoint.dx,thirdEndPoint.dy);
    path.lineTo(size.width, size.height-40.0);
    path.lineTo(size.width, 0.0);
    path.close();

    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    // TODO: implement shouldReclip
    return null;
  }

}

cabeceraDiseno.dart:

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

class CabeceraDiseno extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Column(
      children:<Widget>[
        ClipPath(
          clipper: Cabecera(),
          child: Container(
            //child:IconButton(icon: null, ),
            height: 120.0,
            decoration: BoxDecoration(
              color: Colors.red,
              image: DecorationImage(
                fit:BoxFit.cover,
                image: AssetImage("assets/paisaje1.jpg"),
              ),
            ),
            child: Stack(
              children: <Widget>[
                Opacity(
                  opacity: 0.8,
                  child: Container(
                    decoration:BoxDecoration(
                      color:Colors.blue,
                    ),
                  ),
                ),
                Center(
                  child: Text("DESIGNERS",
                    style: TextStyle(
                      fontSize:25.0,
                      fontFamily: "Lato",
                      fontWeight: FontWeight.w800,
                      color: Colors.white,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
  
}

review.dart:

import 'package:flutter/material.dart';

class Review extends StatelessWidget{

  String name;
  String description;
  String imagen;
  Review(this.imagen,this.name,this.description);
  @override
  Widget build(BuildContext context) {
    // TODO: implement build

    final button = InkWell(
      child: Container(
        width:55.0,
        height:55.0,
        margin: EdgeInsets.only(
          top:20,
          left:80,
          //right: 10.0,
        ),
        decoration: BoxDecoration(
          color:Colors.red,
          borderRadius: BorderRadius.circular(40.0)
        ),
        child: Center(
          child:Icon(
            Icons.mail,
            color: Colors.white,
            size:35,
          ),
        ),
      ),
    );

    final userName =  Container(
      margin: EdgeInsets.only(
        left:20.0,
      ),
      child: Center(
        child:Text(name,
        textAlign: TextAlign.left,
          style: TextStyle(
            fontFamily: "Lato",
            fontSize: 17.0,
            fontWeight: FontWeight.w800,
            color: Colors.black,
          ),
        ),
      ),
    );



    final userDescription= Container(
      margin: EdgeInsets.only(
        left:20.0,
      ),
      child: Center(
        child:Text(description,
          style: TextStyle(
            fontFamily: "Lato",
            fontSize: 13.0,
            color: Colors.black26,
          ),
        ),
      ),
    );

    final userDetails=Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        userName,
        userDescription,
      ],
    );

    final photo=Container(
      margin: EdgeInsets.only(
        top:20.0,
        left:20.0,
      ),
      width: 70.0,
      height: 70.0,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        image: DecorationImage(
          fit: BoxFit.cover,
          image: AssetImage(imagen)
        ),
      ),
    );

    final content=Row(
      children: <Widget>[
        photo,
        userDetails,
        button,
      ],
    );
    return content;
  }

}

review_list.dart:

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

class ReviewList extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children:<Widget>[
        Review("assets/rick.jpg","Geerson", "Experiencia: 4 años"),
        Review("assets/mario.jpg","Kevin", "Experiencia: 5 años"),
        Review("assets/mario.jpg","Jair", "Experiencia: 6 años"),
        Review("assets/rick.jpg","Jose", "Experiencia: 4 años"),
        Review("assets/mario.jpg","Mario", "Experiencia: 5 años"),
        Review("assets/mario.jpg","Rick", "Experiencia: 6 años"),
      ]
    );
  }

}

imagen:

Le he agregado una interacción en el botón de email para que cambie de estado cuando se presione


import 'package:flutter/material.dart';

class Header extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Column(
      children:<Widget>[
        ClipPath(
          clipper: Cabecera(),
          child: Container(
            height: 120.0,
            decoration: BoxDecoration(
              image: DecorationImage(
                fit:BoxFit.cover,
                image: AssetImage("assets/img1.jpg"),
              ),
            ),
            child: Stack(
              children: <Widget>[
                Opacity(
                  opacity: 0.4,
                  child: Container(
                    decoration:BoxDecoration(
                      color:Colors.blue,
                    ),
                  ),
                )
              ],
            ),
          ),
        ),
      ],
    );
  }

}

class Cabecera extends CustomClipper<Path>{
  @override
  Path getClip(Size size) {

    var path= Path();
    path.lineTo(0.0, size.height-40.0);
    var firstControlPoint = new Offset(size.width/6, size.height-60);
    var firstEndPoint = new Offset(size.width/3, size.height-30.0);
    path.quadraticBezierTo(firstControlPoint.dx,firstControlPoint.dy, 
    firstEndPoint.dx,firstEndPoint.dy);
    var secondControlPoint = new Offset( size.width*0.5,size.height);
    var secondEndPoint = new Offset(size.width*(4/6),size.height-30);
    path.quadraticBezierTo(secondControlPoint.dx,secondControlPoint.dy, 
    secondEndPoint.dx,secondEndPoint.dy);
    var thirdControlPoint = new Offset(size.width*(5/6),size.height-60 );
    var thirdEndPoint = new Offset(size.width, size.height-40.0);
    path.quadraticBezierTo(thirdControlPoint.dx,thirdControlPoint.dy, 
    thirdEndPoint.dx,thirdEndPoint.dy);
    path.lineTo(size.width, size.height-40.0);
    path.lineTo(size.width, 0.0);
    path.close();

    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {

    return null;
  }

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

class CardWidgets extends StatefulWidget {
  String url = "assets/img1.jpg";
  String name = "nombre";
  int emission = 1995;
  bool state = true;
  CardWidgets(this.url, this.name, this.emission);

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

class _CardWidgetsState extends State<CardWidgets> {
  bool state = true;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(10.0),
      height: 80.0,
      child: content(),
    );
  }

  Widget content() {
    return Card(
      child: Row(
        children: <Widget>[
          imagen(),
          Expanded(
            child: texto(),
          ),
          buttom(),
        ],
      ),
    );
  }

  Widget imagen() {
    return ClipRRect(
      borderRadius: BorderRadius.circular(50.0),
      child: FadeInImage(
        image: AssetImage(widget.url),
        placeholder: AssetImage('assets/jar-loading.gif'),
        fadeInDuration: Duration(milliseconds: 200),
        width: 60.0,
        height: 60.0,
        fit: BoxFit.cover,
      ),
    );
  }

  Widget texto() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Container(
          margin: EdgeInsets.only(left: 20.0, bottom: 10.0),
          child: Text(
            widget.name,
            textAlign: TextAlign.left,
            style: TextStyle(
              fontSize: 20.0,
            ),
          ),
        ),
        Container(
          margin: EdgeInsets.only(
            left: 20.0,
          ),
          child: Text(
            "Experience: ${widget.emission} years",
            textAlign: TextAlign.left,
            style: TextStyle(fontSize: 16.0, color: Color(0xFFa3a5a7)),
          ),
        ),
      ],
    );
  }

  Widget buttom() {
    return GestureDetector(
      onTap: () {
        setState(() {
          state ? state = false : state = true;
        });
      },
      child: Container(
        margin: EdgeInsets.all(10),
        height: 50.0,
        width: 50.0,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(50),
          color: state ? Colors.red : Color.fromRGBO(215, 215, 215, 1),
        ),
        child: Icon(
          state ? Icons.mail : Icons.mail,
          color: state ? Colors.white : Color.fromRGBO(143, 143, 143, 1),
          size: 30.0,
        ),
      ),
    );
  }
}

import 'package:flutter/material.dart';
import 'package:reto1/widgets/card_widgets.dart';

class Content extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.only(top:70.0),
      color: Colors.white,
      child: ListView(
        children: <Widget>[
          CardWidgets("assets/img1.jpg","primero",1993),
          CardWidgets("assets/img2.jpg","Segundo",1993),
          CardWidgets("assets/img3.jpg","Tercero",1993),
          CardWidgets("assets/img4.jpg","cuarto",1993),
          CardWidgets("assets/img5.jpg","Quinto",1993),
          CardWidgets("assets/img6.jpg","Sexto",1993),
          CardWidgets("assets/img1.jpg","Primero",1993),
          CardWidgets("assets/img2.jpg","Segundo",1993),
        ],
      ),
    );
  }
}
import 'package:flutter/material.dart';
import 'package:reto1/components/content.dart';
import 'package:reto1/components/header.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false,
      home:Stack(
        children: <Widget>[
          Content(),
          Header(),
        ],
      ),
    );
  }
}

Me costo bastante, pero después de revisar bastante la documentación lo logre ❤️

Reto cumplido

Reto completado ✨

Me inspire en este diseño

Codigo en git

Resultado
![](
![](

[]( Una lista funcional, Con filtro por nombre o numero de identificación, consumiendo la los datos desde Firebase.

Creo soy el unico este año estudiando Flutter.

Pues aqui esta el resultado del reto.

Reto terminado (en chrome)

Simple, pero me ayudo a practicar mucho.

https://github.com/GianPierree/flutter-list

Se ve algo sencillo, pero vaya que me costó mucho trabajo, más que todo por la lógica de las cosas. Lo que es el header, está posicionado por sobre la lista, lo que permite que al hacer scroll, no desaparezca el header y la lista pase por bajo del mismo.

Tuve que apoyarme en la comunidad gracias por sus aportes:

main.dart

import 'package:flutter/material.dart';
import 'package:platzi_trips_app/tercer_reto.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
    statusBarColor: Colors.transparent, // transparent status bar
  ));
  runApp(MyAppTercerReto());
}

class MyAppTercerReto extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: //MyHomePage(title: 'Flutter Demo Home Page'),
            Scaffold(
                //body: new DescriptionPlace("Bahamas", 4, descriptionDummy),
                body: Stack(
          children: [
            ListView(
              children: [TercerReto()],
            ),
            BannerHeader("DESINGNERS"),
          ],
        )));
  }
}

tercer_reto.dart

import 'package:flutter/material.dart';

class TercerReto extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(top: 100),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Avatar("assets/img/viajador.jpg"),
              Friend("Freddy Peñalver", "7 años"),
              ReadEmail(true)
            ],
          ),
          Row(
            children: [
              Avatar("assets/img/people.jpg"),
              Friend("Daniel Alvarado", "10 años"),
              ReadEmail(false)
            ],
          ),
          Row(
            children: [
              Avatar("assets/img/viajador.jpg"),
              Friend("Caminantes Dos", "8 años"),
              ReadEmail(true)
            ],
          ),
        ],
      ),
    );
  }
}

class BannerHeader extends StatelessWidget {
  String title = "Popular";
  BannerHeader(this.title);

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    final barra1 = Container(
      height: 120.0,
      decoration: BoxDecoration(
          boxShadow: [
            BoxShadow(
              color: Colors.grey.withOpacity(0.5),
              spreadRadius: 5.0,
              blurRadius: 8.0,
              offset: Offset(1.0, 2.0),
            ),
          ],
          gradient: LinearGradient(
              colors: [Color(0xFF4268D3), Color(0xFF584CD1)],
              begin: FractionalOffset(0.2, 0.0),
              end: FractionalOffset(1.0, 0.6),
              //begin: FractionalOffset.topCenter,
              //end: FractionalOffset.bottomCenter,
              stops: [0.0, 0.6],
              tileMode: TileMode.clamp)),
      child: Center(
        child: Text(
          this.title,
          style: TextStyle(
              fontFamily: "Lato",
              color: Colors.white,
              fontSize: 25.0,
              fontWeight: FontWeight.w900),
        ),
      ),
      alignment: Alignment(-0.9, -0.6),
    );

    final barra2 = Container(
      padding: EdgeInsets.only(
        top: 50.0,
      ),
      height: 130,
      width: 600,
      decoration: BoxDecoration(
          color: Colors.black,
          borderRadius: BorderRadius.vertical(
              bottom:
                  Radius.elliptical(MediaQuery.of(context).size.width, 70.0)),
          boxShadow: [BoxShadow(blurRadius: 30.0)]),
      child: Text(
        "THE RICHEST",
        style: TextStyle(
            fontSize: 30, fontWeight: FontWeight.w900, color: Colors.white),
        textAlign: TextAlign.center,
      ),
    );

    final barra3 = Stack(
      children: [
        Container(
          child: ClipPath(
            //upper clippath with less height
            clipper: WaveClipper(), //set our custom wave clipper.
            child: Container(
              height: 140,
              width: double.infinity,
              alignment: Alignment.center,
              decoration: BoxDecoration(
                image: DecorationImage(
                  fit: BoxFit.cover,
                  image: AssetImage("assets/img/mountain.jpeg"),
                  colorFilter: ColorFilter.mode(
                    Color.fromRGBO(70, 135, 190, 0.80),
                    BlendMode.srcATop,
                  ),
                ),
              ),
              child: Text(
                "DESIGNERS",
                style: TextStyle(
                  fontSize: 20,
                  color: Colors.white,
                  fontFamily: 'Oxygen',
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ),
      ],
    );

    return barra3;
  }
}

//Costom CLipper class with Path
class WaveClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    var path = new Path();
    path.lineTo(0.0, size.height - 38);

    var firstStart = Offset(size.width / 6, size.height - 40);
    //fist point of quadratic bezier curve
    var firstEnd = Offset(size.width / 2 - size.width / 6, size.height - 20);
    //second point of quadratic bezier curve
    path.quadraticBezierTo(
        firstStart.dx, firstStart.dy, firstEnd.dx, firstEnd.dy);

    var secondStart = Offset(size.width / 2, size.height - 5);
    //fist point of quadratic bezier curve
    var secondEnd = Offset(size.width / 2 + size.width / 6, size.height - 20);
    //second point of quadratic bezier curve
    path.quadraticBezierTo(
        secondStart.dx, secondStart.dy, secondEnd.dx, secondEnd.dy);

    var thirdStart = Offset(size.width - (size.width / 6), size.height - 40);
    //third point of quadratic bezier curve
    var thirdEnd = Offset(size.width, size.height - 38);
    //fourth point of quadratic bezier curve
    path.quadraticBezierTo(
        thirdStart.dx, thirdStart.dy, thirdEnd.dx, thirdEnd.dy);

    path.lineTo(size.width, 0.0);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return false;
  }
}

class Avatar extends StatelessWidget {
  String pathImage;
  Avatar(this.pathImage);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 80,
      width: 80,
      margin: EdgeInsets.only(top: 10, left: 10),
      child: CircleAvatar(
        backgroundImage: AssetImage(this.pathImage),
      ),
    );
  }
}

class ReadEmail extends StatelessWidget {
  bool leido;
  ReadEmail(this.leido);

  @override
  Widget build(BuildContext context) {
    final fondo = (this.leido) ? Colors.red : Colors.grey;
    final colorEmail = (this.leido) ? Colors.white : Colors.grey[800];

    return Container(
      height: 80,
      width: 80,
      margin: EdgeInsets.only(top: 10, left: 10),
      child: CircleAvatar(
        child: Icon(
          Icons.email,
          size: 45.0,
          color: colorEmail,
        ),
        backgroundColor: fondo,
      ),
    );
  }
}

class Friend extends StatelessWidget {
  String friend;
  String experience;

  Friend(this.friend, this.experience);

  @override
  Widget build(BuildContext context) {
    // TODO: implement build

    final userName = Container(
      width: 200,
      margin: EdgeInsets.only(left: 20.0),
      child: Text(
        this.friend,
        textAlign: TextAlign.left,
        style: TextStyle(fontFamily: "Lato", fontSize: 17.0),
      ),
    );

    final userExperience = Container(
      width: 200,
      margin: EdgeInsets.only(left: 20.0),
      child: Row(
        children: [
          Text(
            "Experience: " + this.experience,
            textAlign: TextAlign.left,
            style: TextStyle(
                fontFamily: "Lato", fontSize: 13.0, color: Color(0xFFa3a5a7)),
          ),
        ],
      ),
    );

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [userName, userExperience],
    );
  }
}

mi resultado:

El código para resolver el reto se encuentra en GitHub platzi_flutter_reto3

Main.dart

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

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: Scaffold(
          body: Stack(
            children: <Widget>[
              ListView(
                children: <Widget>[
                  Container(
                      margin: EdgeInsets.only(top: 70), child: ReviewList()),
                ],
              ),
              HeaderAppBar()
            ],
          ),
        ));
  }
}

class HeaderAppBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Stack(
      children: <Widget>[
        Header(),
        Row(children: <Widget>[
          Container(
            margin: EdgeInsets.only(left: 20.0, top: 40),
            child: Icon(Icons.menu, size: 28, color: Colors.white),
          ),
          Container(
              margin: EdgeInsets.only(left: 95.0, top: 40),
              child: Text("DESIGNER",
                  textAlign: TextAlign.center,
                  style: TextStyle(
                      fontSize: 16.0,
                      color: Colors.white,
                      fontWeight: FontWeight.w900,
                      shadows: [
                        Shadow(
                          blurRadius: 15.0,
                          color: Colors.black,
                          offset: Offset(3.0, 3.0),
                        )
                      ])))
        ])
      ],
    );
  }
}

class Header extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ClipPath(
      clipper: MyClipper(),
      child: Container(
        height: 170,
        decoration: BoxDecoration(
            color: Colors.white,
            image: DecorationImage(
              colorFilter: ColorFilter.mode(
                  Colors.black.withOpacity(0.7), BlendMode.color),
              fit: BoxFit.fill,
              image: AssetImage("assets/img/cliente3.jpg"),
            )),
      ),
    );
  }
}

class MyClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    Path p = Path();

    p.lineTo(0.0, size.height - 88);
    p.lineTo(size.width / 8, size.height - 88);

    p.quadraticBezierTo(size.width / 8, size.height - 88,
        size.width / 2 - size.width / 8, size.height - 70);

    p.quadraticBezierTo(size.width / 2 - size.width / 8, size.height - 70,
        size.width / 2, size.height - 67);

    p.quadraticBezierTo(size.width / 2, size.height - 67,
        size.width / 2 + size.width / 8, size.height - 70);

    p.quadraticBezierTo(size.width / 2 + size.width / 8, size.height - 70,
        size.width / 2 + size.width / 4 + size.width / 8, size.height - 88);

    p.lineTo(size.width, size.height - 88);
    p.lineTo(size.width, 0);

    p.close();
    return p;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return false;
  }
}

review_list.dart

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

class ReviewList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        new Review(
            "assets/img/people.jpg",
            "Varuna Yasas",
            "1 review · 5 photos",
            "There is an amazing place in Sri Lanka",
            true),
        new Review("assets/img/ann.jpg", "Anahí Salgado", "2 review · 5 photos",
            "There is an amazing place in Sri Lanka", false),
        new Review(
            "assets/img/kiyosaki.jpg",
            "Robert Kiyosaki",
            "2 review · 2 photos",
            "There is an amazing place in Sr kiyosaki",
            true),
      ],
    );
  }
}

review.dart

import 'package:flutter/material.dart';

class Review extends StatelessWidget {
  String pathImage = "assets/img/people.jpg";
  String name = "Varuna Yasas";
  String details = "1 review · 5 photos";
  String comment = "There is an amazing place in Sri Lanka";
  bool showEmail = false;

  Review(this.pathImage, this.name, this.details, this.comment, this.showEmail);

  @override
  Widget build(BuildContext context) {
    final mail = Container(
      margin: EdgeInsets.only(right: 20.0, top: 12),
      height: 48,
      width: 48,
      decoration: BoxDecoration(
        color: this.showEmail ? Colors.red : Colors.grey[300],
        borderRadius: BorderRadius.circular(50),
      ),
      child: Icon(
        Icons.email,
        size: 28,
        color: this.showEmail ? Colors.white : Colors.grey[500],
      ),
    );

    final userInfo = Container(
      margin: EdgeInsets.only(left: 20.0, top: 8),
      child: Text(
        details,
        textAlign: TextAlign.left,
        style: TextStyle(
            fontFamily: "Lato", fontSize: 13.0, color: Color(0xFFa3a5a7)),
      ),
    );

    final userName = Container(
      margin: EdgeInsets.only(left: 20.0, top: 12),
      child: Text(
        name,
        textAlign: TextAlign.left,
        style: TextStyle(fontFamily: "Lato", fontSize: 17.0),
      ),
    );

    final userDetails = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[userName, userInfo],
    );

    final photo = Container(
      margin: EdgeInsets.only(top: 20.0, left: 20.0),
      width: 64.0,
      height: 64.0,
      decoration: BoxDecoration(
          shape: BoxShape.circle,
          image:
              DecorationImage(fit: BoxFit.cover, image: AssetImage(pathImage))),
    );

    return Row(
      children: <Widget>[photo, userDetails, Spacer(), mail],
    );
  }
}

Hola
Acá mi reto. Siento que algo que tiene Flutter es que te permite crear cosas desde 0, sin plantillas como las de xml y 100 flexibles y editables. Sin duda un gran SDK.

En mi caso creé un ListView en forma de gridView. Es interesante ver como funciona MediaQuery.of(context).size a la hora de proporcionar tamaños y márgenes a los widgets.
.

.
.

Bueno, al menos hice lo más importante y le agregue una sombra

![](

//El código donde termine el Clipper y Agregue la sombra 
class MyClipper extends CustomClipper<Path>{
  @override
  getClip(Size size) {
    Path path = Path();
    path.lineTo(0.0, size.height-40);

    var p1 = new Offset(size.width / 6, size.height - 50);
    var p2 = new Offset(size.width / 3, size.height - 30.0);
    path.quadraticBezierTo(p1.dx, p1.dy, p2.dx, p2.dy);

    var p3 = new Offset(size.width*0.5, size.height-10);
    var p4 = new Offset(size.width*(4/6), size.height -30);
    path.quadraticBezierTo(p3.dx, p3.dy, p4.dx, p4.dy);

    var p5 = new Offset(size.width*(5/6), size.height-50);
    var p6 = new Offset(size.width, size.height-40);
    path.quadraticBezierTo(p5.dx, p5.dy, p6.dx, p6.dy);

    path.lineTo(size.width, size.height-40);
    path.lineTo(size.width, 0.0);

    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper oldClipper) => true;
}

class BoxShadowPainter extends CustomPainter{
  @override
  void paint(Canvas canvas, Size size) {
    Path path = Path();
    path.lineTo(0.0, size.height-40);

    var p1 = new Offset(size.width / 6, size.height - 50);
    var p2 = new Offset(size.width / 3, size.height - 30.0);
    path.quadraticBezierTo(p1.dx, p1.dy, p2.dx, p2.dy);

    var p3 = new Offset(size.width*0.5, size.height-10);
    var p4 = new Offset(size.width*(4/6), size.height -30);
    path.quadraticBezierTo(p3.dx, p3.dy, p4.dx, p4.dy);

    var p5 = new Offset(size.width*(5/6), size.height-50);
    var p6 = new Offset(size.width, size.height-40);
    path.quadraticBezierTo(p5.dx, p5.dy, p6.dx, p6.dy);

    path.lineTo(size.width, size.height-40);
    path.lineTo(size.width, 0.0);

    path.close();
    canvas.drawShadow(path, Colors.black, 4.0, false);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
//Aquí use CustomPaint para la sombra :)
home: Scaffold(
        body: Column(
          children: [
            CustomPaint(
              painter: BoxShadowPainter(),
              child: ClipPath(
                clipper: MyClipper(),
                child: CustomAppBar("Bienvenido"),
              ),
            ),
            ReviewList()
          ],
        ),
      )

Reto completado 😃

Cuando el usuario no selecciona una foto de perfil de pone una imagen definida por defecto.

Reto cumplido 😄

Tercer reto:

Trabajé con un dispositivo físico 😄 por eso la calidad de la imagen, espero les guste:

Aspi quedó el mío

Aquí está mi resultado:

![](

main.dart

import 'package:flutter/material.dart';
import 'package:reto3/monster_data.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Final Fantasy Bestiary App',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.teal,
      ),
      home: MyHomePage(title: "Narshe's Mines Bestiary"),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({this.title}) : super();

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
        leading: Container(
          padding: EdgeInsets.all(5),
          child: Icon(
            Icons.menu,
            color: Colors.white,
          ),
        ),
      ),
      body: Column(
        children: <Widget>[
          Flexible(
            child: ListView(
              children: <Widget>[
                MonsterData("Guard",10,false,"assets/img/01-guard.png"),
                MonsterData("Silver Lobo",20,true,"assets/img/02-silver-lobo.png"),
                MonsterData("Megalodoth",3,false,"assets/img/03-megalodoth.png"),
                MonsterData("Wererat",5,true,"assets/img/04-wererat.png"),
                MonsterData("Spritzer",4,false,"assets/img/05-spritzer.png"),
              ],
            ),
          ),
          Container(
            height: 30,
            color: Colors.black54,
            child: Center(
              child: Text(
                "Creatures belong to Square Enix",
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 14,
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

Y monster_data.dart

import 'package:flutter/material.dart';

class MonsterData extends StatelessWidget {

  final String name;
  final int numberKilled;
  final bool isNear;
  final String imagePath;

  MonsterData(this.name, this.numberKilled, this.isNear, this.imagePath);

  @override
  Widget build(BuildContext context) {
    String nearText = isNear ? "NEAR" : "FAR";

    final monsterPicture = Container(
        decoration: BoxDecoration(
          border: Border.all(
            width: 1,
            color: Colors.black54,
          ),
        ),
      child: Container(
        height: 80,
        width: 80,
        margin: EdgeInsets.all(10),
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          image: DecorationImage(
            image: AssetImage(imagePath),
            fit: BoxFit.scaleDown,
          ),
        ),
      )
    );

    final monsterText = Container(
      width: 150,
      decoration: BoxDecoration(
        border: Border.all(
          width: 1,
          color: Colors.black54,
        ),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Container(
            margin: EdgeInsets.all(5),
            child: Text(
              name,
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
                color: Color(0xFF747474),
              ),
            ),
          ),
          Container(
            margin: EdgeInsets.all(5),
            child: Text(
              "Number beaten: $numberKilled",
              style: TextStyle(
                fontSize: 12,
                color: Color(0xFFAFAFAF),
              ),
            ),
          )
        ],
      ),
    );

    final monsterNearInfo = Expanded(
        child: Container(
          height: 100,
          decoration: BoxDecoration(
            border: Border.all(
              width: 1,
              color: Colors.black54,
            ),
          ),
          child: Container(
            margin: EdgeInsets.only(
              left: 5,
            ),
            child: Row(
              children: <Widget>[
                monsterNearIcon(),
                Text(nearText),
              ],
            ),
          )
        )
    );

    return Container(
      height: 100,
      decoration: BoxDecoration(
        border: Border.all(
          width: 1,
          color: Colors.grey,
        )
      ),
      child: Row(
        children: <Widget>[
          monsterPicture,
          Center(child: monsterText),
          monsterNearInfo,
        ],
      ),
    );
  }

  Widget monsterNearIcon() {
    Color color = isNear ? Colors.red : Colors.black;

    return Container(
      margin: EdgeInsets.all(5),
      height: 40,
      width: 40,
      child: Icon(
        Icons.gps_fixed,
        color: Colors.white,
      ),
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: color,
      ),
    );
  }
}```


Claro que requiere también en pubspec.yaml el


assets:
- assets/img/```

Saludos,
Adjunto el reto:

main.dart:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Jugadores de Fútbol',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        fontFamily: 'IBM Plex Sans',
      ),
      home: MyHomePage(title: 'Jugadores de Fútbol'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: Icon(Icons.menu),
        title: Text(
          widget.title,
        ),
        centerTitle: true,
      ),
      body: DesignerList(),
    );
  }
}

designer.dart:

import 'package:flutter/material.dart';

class Designer extends StatelessWidget {
  final ImageProvider photo;
  final String name;
  final int experience;
  final bool read;

  const Designer({this.photo, this.name, this.experience, this.read});

  @override
  Widget build(BuildContext context) {
    final String expTxt = experience < 0
        ? 'No definida'
        : '$experience año' + (experience > 2 ? 's' : '');
    final Color readColor = read ? Colors.grey.shade700 : Colors.white;
    final Color readColorBg = read ? Colors.grey.shade300 : Colors.red.shade700;

    final photoContainer = Container(
      margin: EdgeInsets.only(
        top: 20.0,
        left: 20.0,
      ),
      width: 80.0,
      height: 80.0,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: Colors.black,
        image: DecorationImage(
          image: photo,
          fit: BoxFit.cover,
        ),
      ),
    );

    return Row(
      children: <Widget>[
        photoContainer,
        Container(
          margin: EdgeInsets.only(
            left: 20.0,
            top: 5.0,
          ),
          width: 160.0,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(
                name,
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                ),
              ),
              Text('Experiencia: $expTxt.')
            ],
          ),
        ),
        Container(
          margin: EdgeInsets.only(
            left: 20.0,
            top: 25.0,
          ),
          padding: EdgeInsets.all(8.0),
          decoration: BoxDecoration(
            shape: BoxShape.circle,
            color: readColorBg,
          ),
          child: Icon(
            Icons.mail,
            color: readColor,
          ),
        ),
      ],
    );
  }
}

designer_list.dart:

import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'designer.dart';

class DesignerList extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.vertical,
      children: <Widget>[
        Designer(
          photo: AssetImage('assets/images/cristiano_ronaldo.jpeg'),
          name: 'Cristiano Ronaldo',
          experience: 17,
          read: true,
        ),
        Designer(
          photo: AssetImage('assets/images/neymar.jpeg'),
          name: 'Neymar',
          experience: 10,
          read: true,
        ),
        Designer(
          photo: AssetImage('assets/images/lionel_messi.jpeg'),
          name: 'Lionel Messi',
          experience: 15,
          read: true,
        ),
        Designer(
          photo: AssetImage('assets/images/yerry_mina.jpeg'),
          name: 'Yerry Mina',
          experience: 6,
          read: true,
        ),
        Designer(
          photo: AssetImage('assets/images/unknown_1.jpeg'),
          name: 'Desconocido #1',
          experience: -1,
          read: false,
        ),
        Designer(
          photo: AssetImage('assets/images/unknown_2.jpeg'),
          name: 'Desconocido #2',
          experience: -1,
          read: false,
        ),
        Designer(
          photo: AssetImage('assets/images/radamel_falcao_garcia.jpeg'),
          name: 'Radamel Falcao García',
          experience: 20,
          read: true,
        ),
      ],
    );
  }

}
<h1>Reto cumplido</h1>

repo GitHub

Reto 3

¡Por fin terminé el reto!

Me costó porque pensé que entendía. Revisando la documentación y gracias a las propuesta de @AlexanderZon y @BrayanMM pude ver en que estaba equivocandome.

Les dejo mi propuesta:

Reto cumplido con mi team pokemon actual jajajaaj 😄.

Genial 😄

Listo casi que no 😅
Dejo el repo: https://github.com/Dyabel03/flutter-designers-list

Reto 3 cumplido

**Reto: **

![](

Por fin lo terminé, lo que me tomo más tiempo fue investigar como hacer las curvas en el borde inferior del AppBar.

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(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: Body(),
      ),
    );
  }
}

class Header extends StatelessWidget{

  @override
  Widget build(BuildContext context) {
    return ClipPath(
      clipper: CustomClipPath(),
      child: Container(
        height: 100.0,
        width: double.infinity,
        decoration: BoxDecoration(
          image: DecorationImage(
            fit: BoxFit.cover,
            image: AssetImage("assets/img/background.jpg")
          ),
        ),
        child:  Stack(
            children: <Widget>[
              Opacity(
                opacity: 0.8,
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.blue.shade400,
                  ),
                ),
              ),
              Center(
                  child: Text(
                    "DESIGNERS",
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 18.0,
                        fontWeight: FontWeight.bold
                    ),
                  )
              ),
              Padding(
                padding: const EdgeInsets.only(top: 38.0, left: 20.0),
                child: Icon(
                  Icons.menu,
                  color: Colors.white,
                ),
              )
            ],
          ),
      ),
    );
  }
}

class Designers extends StatelessWidget{

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 60.0),
      child: ListView(
        children: <Widget>[
          ListTile(
            leading: Container(
              height: 50.0,
              width: 50.0,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(50.0),
                image: DecorationImage(
                  fit: BoxFit.cover,
                  image: AssetImage('assets/img/face-model1.jpg'),
                ),
              ),
            ),
            title: Text("Amanda Murpkhy"),
            subtitle: Text("Experience: 04 years"),
            trailing: CircleAvatar(
              backgroundColor: Colors.grey[300],
              child: Icon(
                Icons.mail,
                color: Colors.grey[600],
              ),
            ),
          ),
          Divider(),
          ListTile(
            leading: Container(
              height: 50.0,
              width: 50.0,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(50.0),
                image: DecorationImage(
                  fit: BoxFit.cover,
                  image: AssetImage('assets/img/face-model2.jpg'),
                ),
              ),
            ),
            title: Text("Grace Hartzel"),
            subtitle: Text("Experience: 15 years"),
            trailing: CircleAvatar(
              backgroundColor: Colors.red[800],
              child: Icon(
                Icons.mail,
                color: Colors.white,
              ),
            ),
          ),
          Divider(),
          ListTile(
            leading: Container(
              height: 50.0,
              width: 50.0,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(50.0),
                image: DecorationImage(
                  fit: BoxFit.cover,
                  image: AssetImage('assets/img/face-model3.jpg'),
                ),
              ),
            ),
            title: Text("Bella Hadid"),
            subtitle: Text("Experience: 10 years"),
            trailing: CircleAvatar(
              backgroundColor: Colors.red[800],
              child: Icon(
                Icons.mail,
                color: Colors.white,
              ),
            ),
          ),
          Divider(),
          ListTile(
            leading: Container(
              height: 50.0,
              width: 50.0,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(50.0),
                image: DecorationImage(
                  fit: BoxFit.cover,
                  image: AssetImage('assets/img/face-model4.jpg'),
                ),
              ),
            ),
            title: Text("Julia Bergshoeff"),
            subtitle: Text("Experience: 07 years"),
            trailing: CircleAvatar(
              backgroundColor: Colors.red[800],
              child: Icon(
                Icons.mail,
                color: Colors.white,
              ),
            ),
          ),
          Divider(),
          ListTile(
            leading: Container(
              height: 50.0,
              width: 50.0,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(50.0),
                image: DecorationImage(
                  fit: BoxFit.cover,
                  image: AssetImage('assets/img/face-model5.jpg'),
                ),
              ),
            ),
            title: Text("Malaika Firth"),
            subtitle: Text("Experience: 05 years"),
            trailing: CircleAvatar(
              backgroundColor: Colors.red[800],
              child: Icon(
                Icons.mail,
                color: Colors.white,
              ),
            ),
          ),
          Divider()
        ],
      ),
    );
  }

}

class Body extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Stack(
      children: <Widget>[
        Designers(),
        Header(),
      ],
    );
  }
}

class CustomClipPath extends CustomClipper<Path>{
  @override
  getClip(Size size) {

    Path path = Path();
    path.lineTo(0, size.height*0.75);
    path.quadraticBezierTo(size.width*0.12, size.height*0.70, size.width*0.25, size.height*0.75);
    path.quadraticBezierTo(size.width*0.50, size.height*0.90, size.width*0.75, size.height*0.75);
    path.quadraticBezierTo(size.width*0.87, size.height*0.70, size.width, size.height*0.75);
    path.lineTo(size.width, 0);
    path.close();

    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return false;
  }

}
<main.dart
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
        centerTitle: true,
        title: Text(
          "FreeStyle",
          style: TextStyle(
            fontSize: 30.0,
            fontFamily: "Roboto",
            fontWeight: FontWeight.bold
          ),
        ),
        ),
        body: Stack(
          children: <Widget>[
            DetailsList(),
          ],
        ),
      ),
    );
  }
}
>
<details.dart
import 'package:flutter/material.dart';
    class details extends StatelessWidget{

   String comment = "Comentario";
   String user = "Usuario";
   String pathImage = "assets/img/aczino.jpg";
   details(this.pathImage,this.user,this.comment);
  @override
  Widget build(BuildContext context) {
    // TODO: implement build

    final photo = Container(
        margin: EdgeInsets.only(
          top: 20.0,
          left: 20.0
        ),
      width: 80.0,
      height: 80.0,

      decoration: BoxDecoration(
        shape: BoxShape.circle,
        image: DecorationImage(
          fit: BoxFit.cover,
          image: AssetImage(pathImage)
        )
      ),
    );
    final userComment = Container(
      child: Text(
        comment,
        textAlign: TextAlign.left,
        style: TextStyle(
          fontFamily: "Roboto",
          fontSize: 15.0,
          fontWeight: FontWeight.bold
        ),
      ),
      margin: EdgeInsets.only(
        left: 10.0,
        top: 10.0
      ),
    );

    final userName = Container(
      margin: EdgeInsets.only(
        left: 10.0
      ),
          child: Text(
        user,
        textAlign: TextAlign.left,
            style: TextStyle(
              fontFamily: "Roboto",
              fontSize: 17.0,
              fontWeight: FontWeight.w900
            ),
    ),
    );

    final musicButton = Container(
      alignment: Alignment(1,0),
      child: Icon(
        Icons.play_circle_outline,
        color: Colors.red,
        size: 50.0,
      ),
    );

    final userDetails = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        userName,
        userComment
      ],
    );

    return Row(
      children: <Widget>[
        photo,
        userDetails,
        Expanded(
          child: musicButton,
        )
      ],
    );
  }

    }>
<details_list.dart
import 'package:flutter/material.dart';
import 'details.dart';

class DetailsList extends StatelessWidget{

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        details("assets/img/aczino.jpg","Aczino","Red Bull Internacional 2017"),
        details("assets/img/chuty.jpg","Chuty","FMS España 17-18/18-19"),
        details("assets/img/wos.jpg","Wos","Red Bull Internacional 2018"),
        details("assets/img/teo.jpg","Teorema","BDM Deluxe 2016"),
        details("assets/img/jaze.jpg","Jaze","God Level 3vs3/2vs2 2019"),
        details("assets/img/nekroos.jpg","Nekroos","God Level 3vs3 2019")
      ],
    );
  }
}
>
Este es el codigo del tercer reto

main.dart

<import 'package:flutter/material.dart';
import 'person.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(title: Text('Diseñadores'),),
        body: ListView(
          children: <Widget> [
            Person(),
        Person(),
        Person(),
        Person(),
        Person(),
       Person(),
            Person(),
            Person(),
            Person(),
            Person(),

          ]
      )
      )
        );
       }
      }

>

person.dart

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

class  Person extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build


    return Row (
      children: <Widget>[
        Container(
          height: 80.0,
          width: 80.0,
          decoration: BoxDecoration(
            shape: BoxShape.circle
          ),
              child: Center(
                child: Image(
                    image: NetworkImage('https://image.freepik.com/psd-gratis/hombre-joven-satisfecho-gesto-brazos-cruzados_1459-6066.jpg'),
                    fit: BoxFit.cover

                    ),
              )
        ),
        Column(
          children: <Widget>[
            Text('Juan',
            style: TextStyle(
              fontSize: 45.0,
                  fontWeight: FontWeight.w900,
            ),
            ),
            Text('experiencia 5/5',
            style: TextStyle(
              fontSize: 25.0,
              fontWeight: FontWeight.w500,
            ),
            )
          ],
        ),

        Container(
          margin:   EdgeInsets.only(
            top: 20.0,
            left: 40.0
          ),
          height: 60.0,
          width: 60.0,
          decoration: BoxDecoration(
            shape: BoxShape.circle,
            color: Colors.red,
          ),
          child:  Center(
            heightFactor: 80.0,
            widthFactor: 80.0,
            child: Icon(Icons.mail,
            )
          ),
        )
      ],
    );
  }
}
>

Me costo mucho trabajo la barra superior, pero quedo supercool y aprendi mucho en el camino.
Les recomiendo investiguen estos temas si es que noi saben como hacerlo.
Clipets o clipping: Es una especie de borde personalizado, pero que tu tienes que dibujar por ti mismo.

Curvas de bezier: Unas funcioneas que te ayudaran a crear estas curvas en el dibujado, en mi caso use las cubicas, “cubeTo()”, donde el punto pirncipal es el ultimo punto del lienzo en el que estabas, x1,y1 es el primer punto de conytol, x2, y2 es el segundo punto de control y x3,y3 es el punto al que quieres llegar, asi cree la mitad de la curva y despues hice el proceso inverso para la otra mitad.

Y por ultimo los filtros en la imagen: Lo que hice fue rellenar el contenedor donde tenia el clip de el color que queria y luego puse la imagen encima del contenedor coloreado, le aplique un filtro en forma de patriz donde a la matriz identidad solo le cambie el valor que corresponde al alpha de la imagen por .3.

El resultado de mi reto 3. Fue necesario aprender varios conceptos que todavía no se han visto en el curso para poder resolverlo, entre ellos los Clippers para hacer las formas de la app bar y los Flexible para que el icono de mail se mantuviera alineado y con el ListView la experiencia es muy buena.

Usé la característica de filtro para la imagen del appBar

Dejo el código del ClipPath, que fue lo que se me hizo mas complicado.

class HeaderCustomClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    Path path = Path();

    var sideOffset = 30.0;

    var minHeight = size.height - 50.0;
    var midHeight = size.height - 40.0;
    var maxHeight = size.height - 30.0;

    var halfWidth = size.width / 2;
    var thirdWidth = size.width / 3;

    path.lineTo(0.0, minHeight);

    var fcPoint = new Offset(thirdWidth - sideOffset, minHeight);
    var fePoint = new Offset(thirdWidth, midHeight);
    path.quadraticBezierTo(fcPoint.dx, fcPoint.dy, fePoint.dx, fePoint.dy);

    var scPoint = new Offset(halfWidth, maxHeight);
    var sePoint = new Offset(size.width - thirdWidth, midHeight);
    path.quadraticBezierTo(scPoint.dx, scPoint.dy, sePoint.dx, sePoint.dy);

    var tcPoint = new Offset((size.width - thirdWidth) + sideOffset, minHeight);
    var tePoint = new Offset(size.width, minHeight);
    path.quadraticBezierTo(tcPoint.dx, tcPoint.dy, tePoint.dx, tePoint.dy);

    path.lineTo(size.width, 0.0);

    path.close();

    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) => false;

}
![](https://static.platzi.com/media/user_upload/Captura%20desde%202024-01-23%2020-38-10-d1cc82e0-d096-481b-8dba-d353fa8ef6ff.jpg)
![]()
![]()![](file:///home/user/Pictures/Screenshots/Screenshot%20from%202023-10-06%2012-24-00.png)

![](

mi ejercicio

Reto cumplido
Mi resultado:

Mi solucion al reto

// ignore_for_file: prefer_const_constructors, avoid_web_libraries_in_flutter

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

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

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Drawer Demo'),
      ),
      drawer: Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: const <Widget>[
            DrawerHeader(
              decoration: BoxDecoration(
                color: Colors.green,
              ),
              child: Text(
                'Drawer Header',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                ),
              ),
            ),
            ListTile(
              leading: Icon(Icons.message),
              title: Text('Messages'),
            ),
            ListTile(
              leading: Icon(Icons.account_circle),
              title: Text('Profile'),
            ),
            ListTile(
              leading: Icon(Icons.settings),
              title: Text('Settings'),
            ),
          ],
        ),
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: '',
        theme: ThemeData(
          primarySwatch: Colors.green,
        ),
        home: Scaffold(
            appBar: AppBar(
              title: Text('Directores'),
            ),
            drawer: Drawer(
              child: ListView(
                padding: EdgeInsets.zero,
                children: const <Widget>[
                  DrawerHeader(
                    decoration: BoxDecoration(
                      color: Colors.green,
                    ),
                    child: Text(
                      'Drawer Header',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 24,
                      ),
                    ),
                  ),
                  ListTile(
                    leading: Icon(Icons.message),
                    title: Text('Messages'),
                  ),
                  ListTile(
                    leading: Icon(Icons.account_circle),
                    title: Text('Profile'),
                  ),
                  ListTile(
                    leading: Icon(Icons.settings),
                    title: Text('Settings'),
                  ),
                ],
              ),
            ),
            body: Stack(
              children: <Widget>[
                ListView(
                  children: <Widget>[ReviewList()],
                )
              ],
            )));
  }
}


Hola esto es lo que logre con los conocimientos dados en el curso espero que se de su agrado

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            body: Stack(
      children: [
        TitleDesigners(),
        ListDataDesigners(),
      ],
    )));
  }
}

class DataDesigners extends StatelessWidget {
  String name;
  int experience;
  String link;
  DataDesigners(this.name, this.experience, this.link);
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      decoration: BoxDecoration(
          border: Border(
              bottom: BorderSide(color: Color.fromRGBO(234, 234, 234, 1)))),
      child: Row(
        children: [
          Expanded(
              flex: 2,
              child: Container(
                width: 70,
                height: 70,
                decoration: BoxDecoration(
                    color: Colors.blue,
                    shape: BoxShape.circle,
                    image: DecorationImage(image: AssetImage(link))),
              )),
          Expanded(
              flex: 5,
              child: Container(
                padding: EdgeInsets.only(left: 7),
                height: 90,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Container(
                      child: Text(
                        name,
                        style: TextStyle(
                            fontSize: 16, fontWeight: FontWeight.bold),
                      ),
                    ),
                    Container(
                      margin: EdgeInsets.only(top: 5),
                      child: Text(
                        "Experience: ${experience.toString()} years ",
                        style:
                            TextStyle(fontSize: 16, color: Color(0xFFa3a5a7)),
                      ),
                    )
                  ],
                ),
              )),
          Expanded(
              flex: 2,
              child: Container(
                width: 55,
                height: 55,
                decoration: BoxDecoration(
                    color: Color.fromRGBO(222, 67, 48, 1),
                    shape: BoxShape.circle),
                child: InkWell(
                  child: Icon(
                    Icons.mail,
                    size: 30,
                    color: Colors.white,
                  ),
                ),
              ))
        ],
      ),
    );
  }
}

class ListDataDesigners extends StatelessWidget {
  final List<String> designerNames = [
    "Xiomara Murphy",
    " Santiago Hartzel",
    "Ricardo Hadid",
    "Elena Bergshoeff",
    "Diego Orjuela",
    "Amber, Firth"
  ];
  final List<int> experienceAge = [04, 15, 10, 07, 05, 22];

  final List<String> linkPhoto = [
    "assets/img/xiomara.jpg",
    "assets/img/santiago.jpg",
    "assets/img/ricardo.jpg",
    "assets/img/elena.jpg",
    "assets/img/diego.jpg",
    "assets/img/amber.jpg"
  ];
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(top: 70),
      child: ListView(
        children: [
          DataDesigners(designerNames[0], experienceAge[0], linkPhoto[0]),
          DataDesigners(designerNames[1], experienceAge[1], linkPhoto[1]),
          DataDesigners(designerNames[2], experienceAge[2], linkPhoto[2]),
          DataDesigners(designerNames[3], experienceAge[3], linkPhoto[3]),
          DataDesigners(designerNames[4], experienceAge[4], linkPhoto[4]),
          DataDesigners(designerNames[5], experienceAge[5], linkPhoto[5]),
        ],
      ),
    );
  }
}

class TitleDesigners extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(color: Colors.blue),
      height: 85.0,
      child: Row(
        children: [
          Expanded(
            flex: 1,
            child: InkWell(
              child: Icon(
                Icons.menu,
                color: Colors.white,
                size: 30,
              ),
            ),
          ),
          Expanded(
              flex: 5,
              child: Align(
                alignment: Alignment(-0.35, 0),
                child: Text(
                  "DESIGNERS",
                  style: TextStyle(
                      fontSize: 18,
                      fontWeight: FontWeight.w500,
                      color: Colors.white),
                ),
              ))
        ],
      ),
    );
  }
}

Saludos compañeros,

Comparto mi código: https://github.com/ioviedodev/trip_app (Rama: contactInterface)

Widget generateItem(
      String imageUrl,
      String name,
      int numOfYears,
    ) {
      return Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Container(
            width: 60,
            height: 60,
            margin: EdgeInsets.all(20),
            child: CircleAvatar(
              backgroundImage: NetworkImage(imageUrl),
            ),
          ),
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Text(
                name,
                style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
              ),
              SizedBox(
                height: 12,
              ),
              Text(
                "Experience: $numOfYears years",
                style: TextStyle(fontSize: 15),
              )
            ],
          ),
          SizedBox(
            width: 50,
          ),
          Container(
            width: 60,
            height: 60,
            margin: EdgeInsets.all(20),
            child: CircleAvatar(
              backgroundColor: Colors.red,
              child: Icon(
                Icons.mail,
                color: Colors.white,
              ),
            ),
          ),
        ],
      );
    }

    return Scaffold(
      appBar: AppBar(
        title: Text("Third Challenge"),
      ),
      body: ListView(
        children: [
          generateItem(
            "https://acordesweb.com/img/the-faces-8c5bd2efbf681ee07941973dfb55d256.jpg",
            "Amanda Murphy",
            4,
          ),
          Divider(
            thickness: 5,
          ),
          generateItem(
            "https://i.pinimg.com/564x/b4/69/8b/b4698b5caa57d6c13868b79170c8c945.jpg",
            "Grace Harzel",
            15,
          ),
          Divider(
            thickness: 5,
          ),
          generateItem(
            "https://upload.wikimedia.org/wikipedia/commons/e/ea/Aishwariya_Rai_%28face%29.jpg",
            "Bella Hadid",
            10,
          ),
          Divider(
            thickness: 5,
          ),
          generateItem(
            "https://www.goldennumber.net/wp-content/uploads/2013/08/florence-colgate-england-most-beautiful-face.jpg",
            "Julia Bershoefff",
            7,
          ),
          Divider(
            thickness: 5,
          ),
          generateItem(
            "https://st2.depositphotos.com/4055463/7541/i/950/depositphotos_75416115-stock-photo-beauty-model-girl-portrait.jpg",
            "Malaika Firth",
            5,
          ),
          Divider(
            thickness: 5,
          ),
        ],
      ),
    );