Chào mọi người! Hôm nay chúng ta tiếp tục hành trình học Flutter mỗi ngày nhé. Trong bài hôm qua, chúng ta đã làm quen với TabBar
và Drawer
để tạo giao diện có điều hướng cơ bản. Bài hôm nay sẽ giúp giao diện của chúng ta hiển thị danh sách trông đẹp và gọn gàng hơn nhờ các widget như Card
, ListTile
và tùy biến layout.
Mục tiêu bài học
- Hiểu cách sử dụng
Card
để tạo hiệu ứng nổi, bo góc, bóng đổ. - Sử dụng
ListTile
để tạo các item danh sách gọn gàng. - Tùy chỉnh layout từng item bằng các widget như
Row
,Column
,Padding
... - Ứng dụng
ListView.builder
để hiển thị danh sách động.
Tối ưu giao diện danh sách với Card
và ListTile
Khi hiển thị danh sách dữ liệu, việc trình bày mỗi item một cách rõ ràng và hấp dẫn là rất quan trọng. Flutter cung cấp các widget chuyên dụng để giúp chúng ta làm điều này một cách dễ dàng.
1. Card
: Tạo hiệu ứng nổi và bóng đổ
Card
là một widget Material Design được sử dụng để hiển thị thông tin với hiệu ứng nổi (elevation) và bóng đổ, giúp phân biệt rõ ràng các khối nội dung.
- elevation: Điều chỉnh độ cao của
Card
so với mặt phẳng nền, tạo hiệu ứng đổ bóng. Giá trị càng lớn, bóng đổ càng rõ. - shape: Dùng để tùy chỉnh hình dạng của
Card
, ví dụ như bo tròn các góc vớiRoundedRectangleBorder
.
2. ListTile
: Bố cục chuẩn cho item danh sách
ListTile
là một widget tiện lợi, cung cấp một bố cục chuẩn cho một hàng trong danh sách, giúp bạn tiết kiệm thời gian thiết kế. Nó bao gồm các vị trí phổ biến như:
- leading: Thường dùng cho avatar hoặc icon ở đầu item.
- title: Tiêu đề chính của item.
- subtitle: Mô tả phụ, thường nằm bên dưới tiêu đề.
- trailing: Thường dùng cho các icon điều hướng (ví dụ: mũi tên tiến lên) hoặc các widget nhỏ khác ở cuối item.
- onTap: Xử lý sự kiện khi người dùng chạm vào item.
Ví dụ kết hợp Card và ListTile trong ListView.builder
Đây là một ví dụ minh họa cách chúng ta có thể tạo danh sách người dùng với giao diện đẹp mắt bằng cách kết hợp Card
và ListTile
bên trong ListView.builder
.
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: 'Danh sách người dùng', home: UserListScreen(), ); }
} class UserListScreen extends StatelessWidget { final List<Map<String, String>> users = [ {'name': 'Luân', 'email': 'luan@gmail.com'}, {'name': 'Minh', 'email': 'minh@gmail.com'}, {'name': 'Trang', 'email': 'trang@gmail.com'}, {'name': 'Huy', 'email': 'huy@gmail.com'}, {'name': 'Nam', 'email': 'nam@gmail.com'}, {'name': 'Mai', 'email': 'mai@gmail.com'}, {'name': 'Dung', 'email': 'dung@gmail.com'}, {'name': 'Khoa', 'email': 'khoa@gmail.com'}, ]; Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Danh sách người dùng')), body: ListView.builder( itemCount: users.length, itemBuilder: (context, index) { final user = users[index]; return Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), child: Card( elevation: 3, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: ListTile( leading: CircleAvatar( backgroundColor: Theme.of(context).primaryColorLight, child: Text( user['name']![0], style: TextStyle(color: Theme.of(context).primaryColorDark), ), ), title: Text( user['name']!, style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text(user['email']!), trailing: Icon(Icons.arrow_forward_ios), onTap: () { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Bạn đã chọn ${user['name']}')), ); }, ), ), ); }, ), ); }
}
Tùy biến layout nâng cao cho từng item
Đôi khi, ListTile
không đủ linh hoạt cho các thiết kế phức tạp của bạn. Trong trường hợp đó, bạn hoàn toàn có thể tự xây dựng layout cho từng item bằng cách sử dụng các widget bố cục cơ bản như Container
, Row
, Column
và Padding
.
Ví dụ này cho thấy cách bạn có thể tạo một item tương tự ListTile
nhưng với quyền kiểm soát hoàn toàn từng thành phần:
Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 3, child: Padding( padding: const EdgeInsets.all(12.0), child: Row( children: [ CircleAvatar( backgroundColor: Colors.blueAccent, child: Text(user['name']![0], style: TextStyle(color: Colors.white)), ), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( user['name']!, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), SizedBox(height: 4), Text( user['email']!, style: TextStyle(color: Colors.grey[600]), ), ], ), ), Icon(Icons.more_vert), ], ), ),
)
Kết luận
Trong bài học hôm nay, chúng ta đã cùng nhau làm cho giao diện danh sách trở nên đẹp và chuyên nghiệp hơn bằng cách sử dụng Card
để tạo hiệu ứng nổi bật, ListTile
để nhanh chóng xây dựng các item theo bố cục chuẩn, và học cách tùy chỉnh layout bằng các widget cơ bản khi cần thiết. Những kỹ thuật này là nền tảng vững chắc để bạn tạo ra các danh sách động, hấp dẫn trong ứng dụng Flutter của mình.
Trong bài viết tiếp theo, chúng ta sẽ cùng đi sâu vào một chủ đề thú vị khác: hiển thị hình ảnh trong Flutter, tìm hiểu về Image.network và Image.asset, cùng với cách xử lý lỗi khi tải ảnh.
Cảm ơn các bạn đã theo dõi. Chúc các bạn học tập hiệu quả và hẹn gặp lại trong bài viết tiếp theo nhé! 👋