Reto:
Github
Bienvenida e Introducción
¡Renovaremos este curso!
Desarrollando en Flutter
¿Qué es Flutter?
Dart y Flutter
Sintaxis de Dart
¡Renovaremos este curso!
Flutter para desarrolladores Android, iOS y Xamarin.forms
Flutter para desarrolladores React Native
¿Cómo luce una app construída en Flutter?
Primer reto
Creando mi entorno de desarrollo
¡Renovaremos este curso!
Requerimientos de Hardware y Software
Instalando Flutter en Android Studio y Visual Studio Code
Composición de un proyecto en Flutter
Interfaces en Flutter
¡Renovaremos este curso! Te quedan unos días para concluirlo.
Programación Declarativa en Flutter
Estructura de un programa en Flutter
Hola Mundo en Flutter
Widgets básicos
Widgets con estado y sin estado
Análisis de Interfaces de Usuario en Flutter
Definiendo los layouts de nuestra interfaz
Segundo reto
Widgets sin estado en Flutter
¡Renovaremos este curso! Te quedan unos días para concluirlo.
Flutter Widgets: Container, Text, Icon, Row
Flutter Widgets: Column
Recursos en Flutter: Tipografías y Google Fonts
Widget Image
Widget Apilando Textos
Widgets Decorados
Widget Imagen Decorada
Widget Listview
Widget Button, InkWell
Tercer reto
Widgets con estado en Flutter
¡Renovaremos este curso! Te quedan unos días para concluirlo.
Botones en Flutter
Clase StatefulWidget: Cómo se compone
Widget Floating Action Button
Widgets BottomNavigationBar
Generando Navegación en BottomNavigationBar
Personalizando nuestro BottomNavigation Bar a Cupertino iOS BottomBar
Cuarto reto
Fin del Curso
¡Renovaremos este curso!
Conclusiones
¡Terminamos!
...
Regístrate o inicia sesión para leer el resto del contenido.
Aportes 214
Preguntas 3
Reto:
Github
!! Reto cumplido !!
GitHub: https://github.com/BrayanMamani/Designers
El reto
Intente hacer algo diferente, aun que el codigo quedo algo desordenado.
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 finalizado, basado en https://dribbble.com/shots/6184058-e-commerce-app-exploration
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.
;
@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:
Reto Cumplido!!!
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
[]( 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)
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
 {
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:
Aquí el reto: https://github.com/jjguitar/appAvengersTop
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:
 => 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,
),
],
);
}
}
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: **
 => 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;
}
 {
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),
),
))
],
),
);
}
}
Elegi este diseño: https://dribbble.com/shots/2936433-Lunch-Share-App-UI-UX-Design/attachments/609738
estos son mis avances:
https://drive.google.com/file/d/1c7od01htNkFHQtx8ei0rK3q7u1Ul0w0c/view?usp=share_link
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,
),
],
),
);
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?