
Ê Gen Z! Nghe đây, hôm nay Creyt sẽ "khui" cho mấy đứa một khái niệm mà nghe tưởng khô khan nhưng lại "ngon lành cành đào" trong Flutter: TableRow. Nghe cái tên chắc mấy đứa cũng đoán ra rồi ha? TableRow dịch nôm na là "Hàng trong Bảng". Nhưng nó làm gì, và tại sao mình lại cần nó trong cái vũ trụ Flutter đầy màu sắc này?
1. TableRow là gì và để làm gì? (aka "Cái đĩa cơm trên bàn tiệc data")
Mấy đứa cứ hình dung thế này: trong thế giới lập trình, đôi khi mình cần hiển thị dữ liệu theo kiểu "bảng biểu" cho nó có tổ chức, dễ nhìn. Giống như cái bảng điểm thi đấu game, bảng xếp hạng idol, hay bảng kê khai tài sản của mấy đứa sau khi "cày" game xuyên màn đêm vậy đó.
Trong Flutter, để tạo ra một cái bảng, mình dùng widget Table. Và TableRow chính là "linh hồn" của cái Table đó. Nếu Table là cái bàn ăn hoành tráng mà mấy đứa ngồi vào để "xử lý" data, thì mỗi TableRow chính là một cái "đĩa cơm" được đặt ngay ngắn trên bàn. Mỗi cái đĩa này sẽ chứa các "món ăn" (các widget con như Text, Icon, Container...) xếp cạnh nhau, tạo thành một hàng dữ liệu hoàn chỉnh.
Nói dễ hiểu hơn, TableRow giúp mấy đứa:
- Sắp xếp dữ liệu ngang hàng: Các widget con sẽ tự động được xếp cạnh nhau trong một hàng.
- Tạo cấu trúc rõ ràng: Giúp người dùng dễ dàng đọc và hiểu dữ liệu.
- Tùy chỉnh từng hàng: Mấy đứa có thể "trang trí" riêng cho từng hàng, ví dụ tô màu nền khác nhau, thêm viền cho nó thêm phần "chanh sả".
Nó không phải là "ngôi sao" độc lập đâu nha, nó luôn phải sống trong "mái nhà" là widget Table. Nhớ kỹ: Table chứa một list các TableRow.
2. Code Ví Dụ Minh Họa: "Đĩa cơm" của Creyt
Để mấy đứa dễ hình dung, giờ mình cùng "xắn tay áo" code một cái bảng điểm nhỏ nhắn xinh xắn nhé. Creyt sẽ làm một bảng điểm các môn học.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bảng Điểm Của Creyt',
theme: ThemeData(
primarySwatch: Colors.deepPurple,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bảng Điểm Siêu Cấp Pro'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Table(
// columnWidths: const {
// 0: FlexColumnWidth(2), // Cột 1 rộng gấp đôi
// 1: FlexColumnWidth(1), // Cột 2 bình thường
// 2: FlexColumnWidth(1), // Cột 3 bình thường
// },
border: TableBorder.all(
color: Colors.deepPurple.shade200,
width: 2,
style: BorderStyle.solid,
),
children: <TableRow>[
// Hàng tiêu đề (Header Row)
TableRow(
decoration: BoxDecoration(
color: Colors.deepPurple.shade100,
),
children: const <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Môn Học',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
textAlign: TextAlign.center,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Điểm',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
textAlign: TextAlign.center,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Xếp Loại',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
textAlign: TextAlign.center,
),
),
],
),
// Hàng dữ liệu 1
TableRow(
decoration: const BoxDecoration(
color: Colors.white,
),
children: const <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: Text('Lập Trình Flutter', textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('9.0', textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('A+', textAlign: TextAlign.center),
),
],
),
// Hàng dữ liệu 2 (có màu nền khác để dễ nhìn)
TableRow(
decoration: BoxDecoration(
color: Colors.deepPurple.shade50,
),
children: const <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: Text('Cấu Trúc Dữ Liệu', textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('8.5', textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('A', textAlign: TextAlign.center),
),
],
),
// Hàng dữ liệu 3
TableRow(
decoration: const BoxDecoration(
color: Colors.white,
),
children: const <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: Text('Giải Thuật Nâng Cao', textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('7.8', textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('B+', textAlign: TextAlign.center),
),
],
),
],
),
),
),
);
}
}
Trong ví dụ trên:
- Mình có một
Tablewidget. border: Tạo đường viền cho toàn bộ bảng.children: Đây là nơi chứa cácTableRowcủa chúng ta.- Mỗi
TableRowlại có mộtchildrenkhác, chứa các widget con (ở đây làPaddingbọcText) để tạo thành các ô dữ liệu (cell) trong hàng đó. decorationtrongTableRowgiúp mình tô màu nền riêng cho từng hàng, làm cho bảng "xanh đỏ tím vàng" hơn, dễ đọc hơn.

3. Mẹo Vặt "Hack Não" & Best Practices từ Creyt
- "Cha nào con nấy": Luôn nhớ
TableRowlà con củaTable. Nó không thể sống sót một mình đâu nha. - Đồng bộ số lượng: Tất cả các
TableRowtrong mộtTablephải có SỐ LƯỢNG WIDGET CON (số cột) BẰNG NHAU. Nếu hàng trên có 3 cột, hàng dưới cũng phải có 3 cột. Nếu không, Flutter sẽ "giận dỗi" báo lỗi đấy. - Kiểm soát độ rộng cột: Mấy đứa có thể dùng
columnWidthstrongTableđể điều chỉnh độ rộng của từng cột. Ví dụ,FlexColumnWidthcho phép mấy đứa chia tỷ lệ độ rộng như chia "kẹo" vậy. HoặcIntrinsicColumnWidthsẽ tự động co giãn cột theo nội dung dài nhất, "thông minh" ra phết.- Thử uncomment cái đoạn
columnWidthstrong code ví dụ để xem sự khác biệt nhé!
- Thử uncomment cái đoạn
- Trang trí "đĩa cơm": Dùng
decorationproperty củaTableRowđể thêm màu nền, border cho từng hàng. Rất tiện lợi để tạo các hàng xen kẽ màu sắc (zebra stripes) cho bảng thêm phần chuyên nghiệp. Paddinglà bạn: Đừng quên thêmPaddingcho các widget con bên trongTableRowđể nội dung không bị dính sát vào nhau, nhìn "ngộp" lắm.
4. Ứng Dụng Thực Tế: TableRow "tung hoành" ở đâu?
Mấy đứa có thể thấy các kiểu bảng biểu này "nhan nhản" trong các app/website mà mấy đứa dùng hàng ngày:
- App quản lý tài chính: Bảng kê giao dịch, sao kê ngân hàng, báo cáo thu chi hàng tháng.
- App thể thao: Bảng xếp hạng đội bóng, lịch thi đấu, thống kê cầu thủ.
- App thương mại điện tử: Bảng so sánh thông số kỹ thuật sản phẩm, bảng giá.
- App học tập: Bảng thời khóa biểu, bảng điểm học kỳ.
- Dashboard quản trị: Các biểu đồ, bảng thống kê dữ liệu kinh doanh, lượng truy cập.
Tóm lại, bất cứ khi nào cần hiển thị dữ liệu theo dạng "lưới" có cấu trúc hàng-cột đơn giản, TableRow sẽ là một "chiến binh" đắc lực.
5. Khi nào nên "triệu hồi" TableRow và khi nào nên "cất kiếm"?
Nên dùng TableRow khi:
- Hiển thị dữ liệu tĩnh: Bảng không cần tương tác nhiều (kiểu như bấm vào sắp xếp, lọc dữ liệu).
- Cần kiểm soát chi tiết từng ô/hàng: Mấy đứa muốn mỗi ô có widget riêng, mỗi hàng có màu sắc, trang trí khác nhau một cách linh hoạt.
- Bảng nhỏ và vừa: Với số lượng hàng không quá lớn,
TableRowrất hiệu quả và dễ quản lý. - Trộn lẫn các loại widget: Dễ dàng đặt
Text,Icon,Image,Button... vào chung một ô.
Nên "cất kiếm" và tìm giải pháp khác khi:
- Bảng cần tương tác cao: Nếu mấy đứa muốn có tính năng sắp xếp (sort), lọc (filter), phân trang (pagination) cho bảng dữ liệu, hãy nghĩ ngay đến
DataTablehoặcPaginatedDataTablecủa Flutter. Chúng được thiết kế riêng cho những tác vụ này và sẽ tiết kiệm rất nhiều công sức cho mấy đứa. - Dữ liệu quá lớn (Big Data): Hàng ngàn, hàng chục ngàn hàng dữ liệu?
TablevàTableRowkhông được tối ưu cho việc này. Khi đó,ListView.builderkết hợp với các widget tùy chỉnh cho từng hàng sẽ là lựa chọn tốt hơn để tối ưu hiệu suất (lazy loading). - Cần layout dạng lưới phức tạp hơn: Nếu không phải là bảng "thẳng thớm" mà là các ô có kích thước không đều, chồng chéo, hoặc layout phức tạp hơn, hãy xem xét
GridView,Wraphoặc thậm chíCustomScrollViewvớiSliverGrid.
Thấy chưa? TableRow không chỉ là một cái tên khô khan, nó là một công cụ cực kỳ hữu ích để mấy đứa "trình bày" dữ liệu một cách gọn gàng, đẹp mắt trong app Flutter của mình. Nắm vững nó, mấy đứa sẽ có thêm một "vũ khí" lợi hại trong hành trình chinh phục thế giới lập trình đó!
Thuộc Series: Flutter
Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!