
Chào anh em Gen Z mê code! Anh Creyt đây, hôm nay chúng ta sẽ cùng "phẫu thuật thẩm mỹ" cho cái widget mà nhiều khi anh em thấy nó hơi… "nhạt nhẽo": Table trong Flutter. Cụ thể hơn, chúng ta sẽ "lên đồ" cho nó bằng TableBorder.
TableBorder: "Makeup Artist" cho bảng biểu của bạn
Anh em cứ hình dung thế này: một cái bảng (Table) mà không có đường viền (border) thì nó giống như một tờ giấy trắng tinh, anh em viết chữ lên đấy thì vẫn đọc được thôi, nhưng nhìn nó cứ "trôi tuột", không có điểm nhấn, không phân chia rõ ràng. Thậm chí, anh em nhìn vào còn thấy… chóng mặt nữa là đằng khác.
Đấy là lúc TableBorder xuất hiện như một "makeup artist" chuyên nghiệp. Nó không chỉ đơn thuần là vẽ một cái khung xung quanh bảng, mà nó còn cho phép anh em "tô điểm" từng đường nét bên trong: viền trên, viền dưới, viền trái, viền phải, và đặc biệt là các đường kẻ ngang, kẻ dọc "nội bộ" chia cắt từng ô dữ liệu.
Vậy TableBorder là gì và để làm gì?
Trong Flutter, TableBorder là một class chuyên dùng để định nghĩa các đường viền cho widget Table. Nó giúp anh em:
- Tăng tính dễ đọc: Phân tách rõ ràng từng hàng, từng cột, giúp người dùng dễ dàng theo dõi và so sánh dữ liệu.
- Tạo cấu trúc trực quan: Biến một mớ dữ liệu lộn xộn thành một bố cục có tổ chức, chuyên nghiệp.
- Thẩm mỹ hơn: Đôi khi, một đường viền tinh tế lại làm cho giao diện của anh em "sang chảnh" hơn hẳn.
Nói cách khác, TableBorder là công cụ để anh em biến cái bảng "raw" thành một "data grid" đẹp mắt, dễ hiểu, y như cách anh em kẻ ô ly vào vở để viết cho thẳng hàng vậy.
Code Ví Dụ Minh Hoạ: TableBorder "biến hình" như thế nào?
Anh em xem ví dụ này để thấy TableBorder "phù phép" ra sao nhé. Chúng ta sẽ bắt đầu với một cái bảng cơ bản, sau đó áp dụng các kiểu TableBorder khác nhau.
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: 'TableBorder Demo',
theme: ThemeData(primarySwatch: Colors.blueGrey),
home: Scaffold(
appBar: AppBar(title: const Text('TableBorder Flutter by Creyt')),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Bảng Cơ Bản (TableBorder.all)', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
// Ví dụ 1: TableBorder.all - Tất cả các viền đều giống nhau
Table(
border: TableBorder.all(
color: Colors.blueAccent,
width: 2.0,
style: BorderStyle.solid,
),
children: _buildTableRows(),
),
const SizedBox(height: 30),
const Text('Bảng Nâng Cao (Custom TableBorder)', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
// Ví dụ 2: Custom TableBorder - Kiểm soát từng đường viền
Table(
border: TableBorder(
top: const BorderSide(color: Colors.red, width: 3.0),
bottom: const BorderSide(color: Colors.green, width: 3.0),
left: const BorderSide(color: Colors.purple, width: 1.0, style: BorderStyle.dashed),
right: const BorderSide(color: Colors.purple, width: 1.0, style: BorderStyle.dashed),
horizontalInside: const BorderSide(color: Colors.grey, width: 0.5),
verticalInside: const BorderSide(color: Colors.orange, width: 1.5, style: BorderStyle.dotted),
),
children: _buildTableRows(),
),
const SizedBox(height: 30),
const Text('Bảng Đối Xứng (TableBorder.symmetric)', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
// Ví dụ 3: TableBorder.symmetric - Viền đối xứng
Table(
border: TableBorder.symmetric(
inside: const BorderSide(color: Colors.teal, width: 1.0),
outside: const BorderSide(color: Colors.deepOrange, width: 2.5),
),
children: _buildTableRows(),
),
],
),
),
),
),
);
}
List<TableRow> _buildTableRows() {
return [
TableRow(
decoration: BoxDecoration(color: Colors.blueGrey.shade100),
children: const [
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Tên', style: TextStyle(fontWeight: FontWeight.bold)))),
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Tuổi', style: TextStyle(fontWeight: FontWeight.bold)))),
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Thành Phố', style: TextStyle(fontWeight: FontWeight.bold)))),
],
),
TableRow(
children: const [
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('An'))),
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('22'))),
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Hà Nội'))),
],
),
TableRow(
decoration: BoxDecoration(color: Colors.blueGrey.shade50),
children: const [
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Bình'))),
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('25'))),
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Đà Nẵng'))),
],
),
TableRow(
children: const [
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Cường'))),
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('20'))),
TableCell(child: Padding(padding: EdgeInsets.all(8.0), child: Text('HCM'))),
],
),
];
}
}
Trong ví dụ trên:
TableBorder.all(): Là cách nhanh nhất để áp dụng một kiểu đường viền đồng nhất cho tất cả các cạnh (ngoài và trong) của bảng. Anh em chỉ cần định nghĩacolor,width,stylemột lần là xong.TableBorder()(constructor mặc định): Cho phép anh em kiểm soát từng cạnh một:top,bottom,left,right,horizontalInside(đường kẻ ngang bên trong),verticalInside(đường kẻ dọc bên trong). Mỗi cạnh sẽ nhận một đối tượngBorderSideriêng, nơi anh em tùy chỉnh màu sắc, độ dày và kiểu đường kẻ (solid,dotted,dashed- à mà Flutter hiện tại chỉ hỗ trợsolidthôi nhé,dotted/dashedcần thư viện ngoài hoặc vẽ custom, nhưngBorderStylevẫn có các enum đó để tương thích với web/CSS).TableBorder.symmetric(): Dùng khi anh em muốn các đường viền bên ngoài (outside) có một kiểu, và các đường viền bên trong (inside) có một kiểu khác, nhưng vẫn đối xứng.

Mẹo Vặt (Best Practices) từ Giảng Viên Creyt
- "Nhất quán là sức mạnh": Khi định nghĩa
BorderSide, hãy cố gắng tái sử dụng cácBorderSideobject hoặc các giá trị màu/độ dày. Đừng mỗi chỗ một kiểu, nhìn cái bảng nó sẽ "loạn thị" ngay. Ví dụ, nếu tất cảhorizontalInsideđều màu xám nhạt, hãy tạo mộtconst BorderSide kDefaultHorizontalBorder = BorderSide(color: Colors.grey, width: 0.5);để dùng lại. - "Đơn giản là bạn": Đừng cố gắng làm cho mọi đường viền đều khác biệt. Đôi khi, một cái bảng với đường viền ngoài đậm, đường viền trong nhạt là đã đủ đẹp và dễ đọc rồi. "Less is more" mà.
- "Test với màu mè": Nếu anh em không chắc đường viền của mình đang ở đâu hoặc có hiển thị đúng không, hãy tạm thời set
color: Colors.red, width: 3.0choBorderSideđó. Nó sẽ "nhảy" ra ngay cho anh em thấy. - "Hòa mình vào Theme": Thay vì dùng
Colors.red,Colors.bluetùy tiện, hãy cố gắng lấy màu từTheme.of(context).colorSchemehoặc cácColorSchemeđã định nghĩa để bảng biểu của anh em trông "ăn nhập" với tổng thể ứng dụng hơn. TableBorder.allcho "mì ăn liền": Khi anh em cần nhanh gọn lẹ một cái bảng có đường viền đều đặn,TableBorder.all()là cứu tinh. Còn khi cần "độ" từng chi tiết, mới dùngTableBorder()constructor đầy đủ nhé.
Ứng Dụng Thực Tế: TableBorder có mặt ở đâu?
Anh em cứ nghĩ đến bất kỳ đâu cần hiển thị dữ liệu có cấu trúc dạng lưới là TableBorder có thể "nhảy" vào:
- Dashboard và Báo Cáo: Các ứng dụng quản lý tài chính, phân tích dữ liệu (như Google Analytics, các app quản lý kho hàng, CRM) thường dùng bảng để hiển thị các chỉ số, thống kê.
TableBordergiúp phân chia rõ ràng các cột "doanh thu", "lợi nhuận", "số đơn hàng"... - So Sánh Sản Phẩm: Trên các trang thương mại điện tử (Shopee, Lazada, Tiki), khi anh em xem bảng so sánh tính năng giữa các sản phẩm, đó chính là
TablevớiTableBorderđang "làm nhiệm vụ" đấy. - Lịch Biểu, Thời Khóa Biểu: Các ứng dụng lịch, quản lý công việc đôi khi dùng
Tableđể hiển thị các khung giờ, sự kiện trong ngày/tuần, và đường viền giúp phân biệt các khoảng thời gian. - Bảng Xếp Hạng (Game): Một số game có bảng xếp hạng người chơi, điểm số,
TableBordergiúp bảng này trông "nghiêm túc" và dễ đọc hơn.
Thử Nghiệm và Khi Nào Nên Dùng?
Thử nghiệm:
- "Zebra Striping" (Sọc ngựa vằn): Anh em thử kết hợp
TableBordervớidecorationcủaTableRow(như trong ví dụ anh Creyt đã làm vớiBoxDecoration(color: Colors.blueGrey.shade100)). Thay đổi màu nền của các hàng xen kẽ để tạo hiệu ứng sọc, vừa đẹp mắt vừa dễ đọc. - Không viền nhưng vẫn phân tách: Thử set
BorderSide(width: 0.0)hoặcBorderStyle.nonecho một số cạnh. Đôi khi, việc không có viền lại tạo ra hiệu ứng "khoảng trắng" (whitespace) tốt hơn, nhưng vẫn có các đường viền khác để giữ cấu trúc.
Nên dùng TableBorder cho case nào?
- Khi dữ liệu có tính chất "số liệu, thống kê": Cần sự chính xác, rõ ràng trong từng ô.
- Khi cần "so sánh trực quan": Người dùng cần đặt các giá trị cạnh nhau để đối chiếu.
- Khi thiết kế yêu cầu "tính trang trọng, cấu trúc chặt chẽ": Ví dụ, báo cáo tài chính, danh sách điểm số, v.v.
Không nên lạm dụng: Nếu anh em chỉ cần hiển thị một danh sách đơn giản, không có nhiều cột và không cần phân tách quá chặt chẽ, ListView hoặc một Column với các Row thông thường sẽ phù hợp và hiệu quả hơn. Table và TableBorder có "chi phí" render cao hơn một chút vì nó phải tính toán vị trí và kích thước của các ô để căn chỉnh.
Vậy đó, anh em. TableBorder tuy nhỏ mà có võ, biến những con số khô khan thành tác phẩm nghệ thuật dễ đọc, dễ nhìn. Hãy thực hành và sáng tạo với nó nhé! Anh Creyt tin anh em sẽ "biến hình" được những cái bảng "xấu lạ" thành "siêu phẩm" visual!
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é!