Một hàng nhãn công nghệ thường nhìn ổn khi chỉ có hai Chip ngắn. Thêm nhãn tiếng Việt dài hoặc thu hẹp cửa sổ, Row không tự chuyển các Chip còn lại xuống hàng. Wrap phù hợp khi yêu cầu là một nhóm phần tử lần lượt lấp đầy từng dòng rồi tiếp tục ở dòng mới.
Bài đối chiếu API Flutter Wrap và Row hiện hành ngày 05/11/2026. Ví dụ Dart được rà thủ công theo hợp đồng widget; chưa chạy Flutter SDK, build app hay đo layout trên thiết bị. Các bước quan sát bên dưới là checklist để bạn tự chạy trong project, không phải ảnh chụp hoặc số đo đã thu được.
Chọn đúng kiểu bố trí cho nhóm nhãn
Row bố trí con trong một hàng ngang. Wrap có thể tạo nhiều run, tức nhiều lượt bố trí theo trục chính; với hướng ngang mặc định, mỗi run thường được nhìn như một dòng. Khi phần tử tiếp theo không còn vừa, Wrap bắt đầu run mới.
Đừng nhầm nhóm Chip xuống dòng với nội dung Text xuống dòng bên trong một Chip. Wrap quyết định vị trí của các widget con. Một nhãn riêng quá dài vẫn cần quy tắc riêng cho nội dung và chiều rộng của chính widget đó.
1. Demo có giới hạn chiều rộng rõ ràng
Dùng đoạn sau làm nội dung lib/main.dart trong project Flutter đã tạo. Ví dụ không cần package bên ngoài:
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: TagsDemo()));
class TagsDemo extends StatelessWidget {
const TagsDemo({super.key});
static const tags = <String>[
'Dart',
'Flutter',
'Kiểm thử giao diện',
'Mobile',
'Backend',
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Nhóm nhãn tự xuống dòng')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Align(
alignment: Alignment.topLeft,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 320),
child: Wrap(
spacing: 8,
runSpacing: 12,
children: tags.map((tag) => Chip(
label: Text(tag),
)).toList(),
),
),
),
),
);
}
}
ConstrainedBox giới hạn nhóm nhãn tối đa 320 logical pixel, đồng thời vẫn chịu ràng buộc từ vùng cha. Đây không phải cam kết rằng đúng ba Chip sẽ nằm trên dòng đầu: số lượng phụ thuộc font, theme, text scale và kích thước thực của từng Chip.
SingleChildScrollView cho phép cuộn dọc nếu vùng nội dung thấp. Nó không biến Wrap thành danh sách lazy. Toàn bộ children trong ví dụ vẫn được tạo từ danh sách tags.
2. Tách khoảng cách trong dòng khỏi khoảng cách giữa dòng
spacing: 8 tạo khoảng cách giữa các phần tử kề nhau theo trục chính. Với Wrap ngang, đó là khoảng cách giữa các hộp Chip trong cùng run. runSpacing: 12 đặt khoảng cách giữa các run theo trục còn lại.
Hai số này không thay thế padding của trang hoặc padding bên trong Chip. Nếu tổng khoảng trắng nhìn lớn hơn dự kiến, kiểm tra thêm các khoảng đệm và vùng chạm do component con hoặc theme tạo ra. Đo bounds của widget trước khi kết luận Wrap cộng sai spacing.
Trong ví dụ, alignment mặc định bắt đầu mỗi run từ phía start theo hướng văn bản. Nếu cần đổi căn hàng, xem alignment; nếu cần căn cả tập hợp các run trong vùng trống, xem runAlignment. Chúng giải quyết hai cấp bố trí khác nhau.
Kiểm tra với bề rộng và nội dung thay đổi
Đầu tiên chạy với nhóm năm nhãn, sau đó thu hẹp vùng hiển thị. Kiểm tra các Chip chuyển sang run tiếp theo khi không còn chỗ, vẫn giữ thứ tự dữ liệu và không bị một container có chiều cao cố định cắt mất dòng cuối.
Tiếp theo tăng cỡ chữ trong cài đặt thiết bị hoặc môi trường test của app. Thêm một nhãn rất dài và kiểm tra riêng cách component con xử lý nó. Nếu thiết kế cần rút gọn nhãn, đặt chính sách maxLines và overflow phù hợp với khả năng đọc; không coi xuống dòng giữa các Chip là giải pháp cho mọi nhãn dài.
Đổi danh sách thành rỗng rồi một phần tử để kiểm tra trạng thái ít dữ liệu. Đổi direction sang dọc chỉ khi yêu cầu thiết kế thật sự là lấp theo cột: ý nghĩa của trục spacing và runSpacing cũng đổi theo hướng ấy.
Lỗi thường gặp và phạm vi sử dụng
Đặt Wrap ngang trong một vùng có chiều rộng không bị giới hạn có thể khiến nó không xuống dòng theo mong đợi. Xác định bề rộng khả dụng từ layout cha trước khi chỉnh spacing. Không bọc từng Chip bằng Expanded như trong Row: Expanded yêu cầu cha Flex phù hợp, trong khi Wrap là kiểu bố trí khác.
Dùng Wrap cho nhóm nhãn có số lượng vừa phải và phần tử có chiều rộng khác nhau. Với dữ liệu dài cần dựng theo nhu cầu, xem các widget danh sách hoặc grid phù hợp. Bắt đầu bằng yêu cầu hiển thị và ràng buộc thực tế; việc thay Row bằng Wrap chỉ đúng khi sản phẩm chấp nhận nhiều dòng.

