Nell'articolo precedente abbiamo visto come costruire una semplice ListView con dati casuali di esempio. Partendo da quel progetto, lo amplieremo per migliorare l'aspetto degli elementi e per introdurre la gestione dello stato.
Un nuovo widget per gli elementi della ListView
Nella cartella components creiamo un nuovo file circleimage.dart con questo codice:
import 'package:flutter/material.dart';
class CircleImage extends StatelessWidget {
const CircleImage({
Key? key,
this.imageProvider,
this.imageRadius = 20,
}) : super(key: key);
final double imageRadius;
final ImageProvider? imageProvider;
@override
Widget build(BuildContext context) {
return CircleAvatar(
backgroundColor: Colors.black,
radius: imageRadius,
child: CircleAvatar(
radius: imageRadius - 1,
backgroundImage: imageProvider,
),
);
}
}
Useremo questo widget per aggiungere una immagine (circolare con un bordo nero di 1 pixel) ad ogni elemento della listview.
Modifichiamo anche la classe Item nel file /models/item.dart per aggiungere il nuovo campo image.
class Item {
final String image;
final String firstName;
final String lastName;
final String email;
const Item(
{required this.image,
required this.firstName,
required this.lastName,
required this.email});
}
e il file /pages/listviewpage.dart per valorizzare sempre il nuovo campo
...
var faker = Faker();
for (int i = 0; i < 20; i++) {
itemTestData.add(Item(
image: "https://picsum.photos/140/140?random=${i}",
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email()));
}
...
Nella cartella components modifichiamo il carditem.dart con questo codice:
import '../components/circleimage.dart';
...
Widget build(BuildContext context) {
return ListTile(
leading: CircleImage(
imageProvider: NetworkImage(item.image),
imageRadius: 20),
title: Text("${item.firstName} ${item.lastName}"),
subtitle: Text(item.email));
}
...
Con le modifiche appena realizzate, gli elementi della ListView, avranno più o meno un aspetto del genere:
Una nuova card per gli elementi della ListView
Nella cartella components modifichiamo ulteriormente il carditem.dart con questo codice:
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(3.0),
child: Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CircleImage(
imageProvider: NetworkImage(item.image), imageRadius: 20),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('${item.firstName} ${item.lastName}',
style: const TextStyle(fontWeight: FontWeight.w700)),
Text(
item.email,
),
],
),
),
],
),
),
),
);
}
per ottenere un aspetto simile a questo (ombreggiatura, bordi arrotondati e in risalto):
Gestiamo lo stato: un pulsante su ogni elemento
All'elenco dei children aggiungiamo una piccola icona (un cuore rosso) su ogni elemento, che se cliccato farà apparire una notifica:
...
children: [
CircleImage(
imageProvider: NetworkImage(item.image), imageRadius: 20),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('${item.firstName} ${item.lastName}',
style: const TextStyle(fontWeight: FontWeight.w700)),
Text(
item.email,
),
],
),
),
IconButton(
// 4
icon: const Icon(Icons.favorite_border),
iconSize: 30,
color: Colors.red[400],
// 5
onPressed: () {
const snackBar =
SnackBar(content: Text('Favorite Pressed'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}),
],
...
Per gestire lo stato del pulsante appena definito, facciamo un refactoring di CardItem da StatelessWidget a StatefulWidget aggiungendo la variabile _isFavorited per memorizzare lo stato corrente del pulsante :
....
class CardItem extends StatefulWidget {
const CardItem({Key? key, required this.item}) : super(key: key);
final Item item;
@override
State<CardItem> createState() => _CardItemState();
}
class _CardItemState extends State<CardItem> {
bool _isFavorited = false;
@override
Widget build(BuildContext context) {
return Padding(
...
e modifichiamo l'evento sul cuoricino, in modo che alterni due stati:
...
IconButton(
icon: Icon(
_isFavorited ? Icons.favorite : Icons.favorite_border),
iconSize: 30,
color: Colors.red,
onPressed: () {
setState(() {
_isFavorited = !_isFavorited;
});
const snackBar =
SnackBar(content: Text('Favorite Pressed'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}),
...
Con queste modifiche, su ogni elemento sarà possibile conservare lo stato del click sul cuoricino, che cambierà colore
La nuova versione della nostra ListView ora è completa.
Commenti
Posta un commento