Mettere tutto insieme e rendere la card riutilizzabile
Ultimo passo: uniamo i pezzi in un unico widget ProfileCard che riceve i dati dall'esterno tramite parametri. Così potrai usarlo in qualunque schermata, anche dentro una ListView.
Alcune rifiniture finali:
SafeArea evita che il contenuto finisca sotto la notch o la barra di sistema;
SingleChildScrollView previene l'overflow verticale quando la tastiera si apre o lo schermo è piccolo;
ConstrainedBox con maxWidth evita che la card diventi larghissima su tablet e desktop;
const davanti ai widget statici aiuta le performance.
Prova a cambiare crossAxisAlignment, i valori di flex e il padding: è il modo migliore per interiorizzare come ragiona il motore di layout di Flutter.
import 'package:flutter/material.dart';
class ProfileCard extends StatelessWidget {
const ProfileCard({
super.key,
required this.name,
required this.role,
required this.posts,
required this.followers,
required this.following,
});
final String name;
final String role;
final String posts;
final String followers;
final String following;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: const [
BoxShadow(color: Color(0x14000000), blurRadius: 16, offset: Offset(0, 6)),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
const CircleAvatar(
radius: 32,
backgroundColor: Color(0xFFE3E5F0),
child: Icon(Icons.person, size: 34, color: Colors.indigo),
),
const SizedBox(width: 16),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 4),
Text(
role,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black54),
),
],
),
),
const Icon(Icons.more_vert, color: Colors.black45),
],
),
const Divider(height: 32),
Row(
children: [
Expanded(child: _StatItem(value: posts, label: 'Post')),
Expanded(child: _StatItem(value: followers, label: 'Follower')),
Expanded(child: _StatItem(value: following, label: 'Seguiti')),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(
flex: 2,
child: ElevatedButton.icon(
onPressed: () {},
icon: const Icon(Icons.person_add_alt),
label: const Text('Segui'),
style: ElevatedButton.styleFrom(minimumSize: const Size.fromHeight(48)),
),
),
const SizedBox(width: 12),
Expanded(
child: OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(minimumSize: const Size.fromHeight(48)),
child: const Text('Messaggio'),
),
),
],
),
],
),
);
}
}
class _StatItem extends StatelessWidget {
const _StatItem({required this.value, required this.label});
final String value;
final String label;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(value, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 2),
Text(label, style: const TextStyle(color: Colors.black54, fontSize: 13)),
],
);
}
}
// Uso nella HomePage
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF2F3F7),
appBar: AppBar(title: const Text('Card profilo')),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 480),
child: const ProfileCard(
name: 'Giulia Ferrari',
role: 'Mobile Developer specializzata in Flutter',
posts: '128',
followers: '4.2k',
following: '310',
),
),
),
),
),
);
}
}
Risultato atteso
La card profilo è completa, riutilizzabile con parametri diversi, non va in overflow su schermi piccoli e resta ben proporzionata su tablet e desktop.