Bạn có bao giờ tự hỏi làm thế nào các ứng dụng hiển thị thư viện ảnh đẹp mắt, danh sách sản phẩm gọn gàng theo cột, hay thậm chí là các dashboard phức tạp với nhiều ô thông tin được sắp xếp khoa học? Câu trả lời chính là nhờ những widget như GridView
.
Trong Flutter, GridView
không chỉ đơn thuần là một cách để sắp xếp các item theo dạng lưới, mà còn cung cấp nhiều tùy chọn linh hoạt để bạn tùy chỉnh giao diện, tối ưu hóa hiệu suất cho các danh sách lớn, và tạo ra những trải nghiệm người dùng mượt mà và hấp dẫn.
Bài viết này sẽ đưa bạn đi từng bước, từ những khái niệm cơ bản nhất về GridView
, qua các cách tạo và sử dụng phổ biến, đến những lưu ý quan trọng và cách xử lý các lỗi thường gặp. Hãy cùng nhau khám phá sức mạnh của bố cục lưới trong Flutter nhé!
🧠 Mục tiêu bài học
- Biết cách tạo
GridView
với dữ liệu tĩnh và động. - Hiểu sự khác nhau giữa
GridView.count
,GridView.builder
và làm quen vớiGridView.extent
. - Thực hành hiển thị danh sách ảnh hoặc nội dung chia cột đẹp mắt, tùy chỉnh khoảng cách và tỷ lệ khung hình.
📦 GridView là gì?
Trong Flutter, GridView
là một widget mạnh mẽ giúp hiển thị các item theo dạng lưới hai chiều, cho phép cuộn cả theo chiều dọc và chiều ngang (tùy cấu hình). Đây là công cụ lý tưởng cho:
- Thư viện ảnh
- Danh sách sản phẩm
- Bố cục nhiều cột trong một không gian cuộn
🚀 Các cách tạo GridView
Flutter cung cấp một số constructor khác nhau cho GridView
, mỗi constructor phù hợp với các trường hợp sử dụng khác nhau:
1. GridView.count() – dễ dùng, chỉ định số cột
Đây là cách đơn giản nhất để tạo GridView
khi bạn biết trước số cột mong muốn. Tất cả các item con sẽ được tạo ra cùng một lúc.
GridView.count( crossAxisCount: 2, children: [ Container(color: Colors.red), Container(color: Colors.green), Container(color: Colors.blue), Container(color: Colors.orange), ],
)
Thuộc tính quan trọng:
crossAxisCount
: Xác định số lượng cột hiển thị trên mỗi hàng. Các widget con sẽ tự động được sắp xếp để lấp đầy các cột này.
2. GridView.builder() – linh hoạt và tối ưu
Tương tự như ListView.builder()
, constructor này chỉ tạo ra các item khi chúng sắp được hiển thị trên màn hình, giúp tối ưu hóa hiệu suất đáng kể khi làm việc với danh sách dữ liệu lớn hoặc dữ liệu động. Bạn cần cung cấp một SliverGridDelegate
để định nghĩa bố cục lưới.
GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 10, mainAxisSpacing: 10, ), itemCount: 6, itemBuilder: (context, index) { return Container( color: Colors.primaries[index % Colors.primaries.length], child: Center( child: Text('Mục $index'), ), ); },
)
Thuộc tính quan trọng trong SliverGridDelegateWithFixedCrossAxisCount
:
crossAxisCount
: Số cột trên mỗi hàng.crossAxisSpacing
: Khoảng cách giữa các cột.mainAxisSpacing
: Khoảng cách giữa các hàng.childAspectRatio
: Tỷ lệ giữa chiều rộng và chiều cao của mỗi ô (width / height). Giá trị 1.0 tạo ra các ô vuông.
3. GridView.extent() – chỉ định kích thước tối đa của ô
Với GridView.extent()
, bạn chỉ định kích thước tối đa cho phép của mỗi ô theo chiều ngang (maxCrossAxisExtent
), và Flutter sẽ tự động tính toán số cột phù hợp dựa trên không gian có sẵn.
GridView.extent( maxCrossAxisExtent: 150, // Kích thước tối đa của mỗi ô theo chiều ngang crossAxisSpacing: 10, mainAxisSpacing: 10, children: List.generate( 8, (index) => Container( color: Colors.amber[100 * (index % 9)], child: Center(child: Text('Item $index')), ), ),
)
Thuộc tính quan trọng:
maxCrossAxisExtent
: Kích thước tối đa của mỗi ô theo chiều ngang. Flutter sẽ cố gắng tạo ra các cột sao cho không có ô nào vượt quá kích thước này.
Ví dụ đầy đủ
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( home: DanhSachAnh(), ); }
} class ListImage extends StatelessWidget { final List<String> imageUrls = List.generate( 8, (index) => 'https://picsum.photos/200/300?random=$index', ); Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Bộ sưu tập')), body: Padding( padding: const EdgeInsets.all(10), child: GridView.builder( itemCount: imageUrls.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 10, mainAxisSpacing: 10, ), itemBuilder: (context, index) { return ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.network( imageUrls[index], fit: BoxFit.cover, ), ); }, ), ), ); }
}
Ghi nhớ khi làm việc với GridView:
- Sử dụng
GridView.count
cho các lưới có số cột cố định và số lượng item nhỏ. GridView.builder
là lựa chọn tốt nhất cho danh sách dữ liệu động hoặc số lượng item lớn để tối ưu hiệu suất.GridView.extent
hữu ích khi bạn muốn các ô có kích thước chiều ngang tối đa nhất định và để Flutter tự động tính toán số cột.- Luôn chú ý đến các thuộc tính
crossAxisSpacing
,mainAxisSpacing
, vàchildAspectRatio
để tạo bố cục lưới đẹp và phù hợp. - Khi
GridView
là con của các widget không giới hạn kích thước (nhưColumn
,Row
), hãy bọc nó trongExpanded
hoặcSizedBox
để tránh lỗi bố cục.
Các lỗi thường gặp và cách khắc phục:
- GridView không cuộn được: Kiểm tra xem
GridView
có được bọc trong một widget có kích thước xác định theo hướng cuộn hay không (ví dụ:Expanded
,SizedBox
). - Lỗi tràn pixel: Điều chỉnh
crossAxisCount
,crossAxisSpacing
,mainAxisSpacing
, vàchildAspectRatio
sao cho phù hợp với kích thước màn hình và nội dung item. - Hiệu suất kém với
GridView.count
và danh sách lớn: Chuyển sang sử dụngGridView.builder
để chỉ tạo các item hiển thị trên màn hình. - Giao diện lưới không đều: Đảm bảo các item con có kích thước hoặc tỷ lệ khung hình tương đồng, hoặc sử dụng
childAspectRatio
để kiểm soát tỷ lệ của các ô lưới. - Lỗi khi tải ảnh từ mạng: Sử dụng các thư viện quản lý cache ảnh (
cached_network_image
) và xử lý các trường hợp lỗi tải ảnh.
Kết luận: Làm chủ bố cục lưới với GridView
Trong bài học này, chúng ta đã trang bị cho mình kiến thức về GridView
và các biến thể của nó trong Flutter. Từ việc tạo các lưới đơn giản đến việc xây dựng các bố cục phức tạp và tối ưu hóa hiệu suất cho danh sách lớn, GridView
mang đến sự linh hoạt tuyệt vời cho việc hiển thị dữ liệu dạng lưới.
Hãy thực hành và thử nghiệm với các thuộc tính khác nhau để hiểu rõ hơn về cách GridView
hoạt động và cách bạn có thể tận dụng nó để tạo ra những giao diện người dùng ấn tượng.
Hẹn gặp lại bạn trong những bài học tiếp theo, nơi chúng ta sẽ tiếp tục khám phá những khía cạnh thú vị khác của Flutter! 😊