Flutter: Layout (Bố cục) trong Flutter
Mục lục bài viết
- Bố cục một widget
- Bố trí nhiều widget theo chiều dọc và chiều ngang
- Các widget bố cục phổ biến
- Ràng buộc
- Các nguồn tham khảo
Vấn đề ở đây là gì?
- Widget là các lớp được sử dụng để xây dựng giao diện người dùng.
- Các widget được sử dụng cho cả bố cục và phần tử giao diện người dùng.
- Sử dụng các widget đơn giản để tạo các widget phức tạp.
Cốt lõi của cơ chế bố trí của Flutter là các widget. Trong Flutter, hầu hết mọi thứ đều là widget - ngay cả các mô hình bố cục cũng là widget. Hình ảnh, biểu tượng và văn bản mà bạn thấy trong ứng dụng Flutter đều là widget. Ngay cả những thứ bạn không thấy cũng là các widget, chẳng hạn như các hàng, cột và lưới sắp xếp, ràng buộc và căn chỉnh các widget hiển thị.
Bạn tạo bố cục bằng cách soạn các widget để xây dựng các widget phức tạp hơn. Ví dụ: ảnh chụp màn hình đầu tiên bên dưới đây hiển thị 3 biểu tượng có nhãn bên dưới mỗi biểu tượng:
Ảnh chụp màn hình thứ hai hiển thị bố cục trực quan, hiển thị một hàng gồm 3 cột trong đó mỗi cột chứa một biểu tượng và nhãn.
Lưu ý: Hầu hết các ảnh chụp màn hình trong hướng dẫn này được hiển thị với việc đặt
debugPaintSizeEnabled
thành true để bạn có thể thấy bố cục trực quan. Để biết thêm thông tin, hãy xem Trực quan gỡ lỗi các vấn đề về bố cục, là một phần trong Sử dụng trình kiểm tra Flutter.
Dưới đây là sơ đồ của cây widget cho giao diện người dùng này:
Ở hình trên bạn thấy các container được hiển thị bằng màu hồng. Container là một lớp widget cho phép bạn tùy chỉnh widget con của nó. Sử dụng Container
khi bạn muốn thêm phần đệm (margin), lề (padding), đường viền (border) hoặc màu nền (background) để đặt tên cho một số khả năng của nó.
Trong ví dụ này, mỗi widget Text được đặt trong một Container
để thêm lề (margin). Toàn bộ Row cũng được đặt trong một Container
để thêm đệm (padding) xung quanh hàng.
Phần còn lại của giao diện người dùng trong ví dụ này được kiểm soát bởi các thuộc tính. Đặt màu của Icon thì ta sử dụng thuộc tính color
. Sử dụng thuộc tính Text.style
để đặt phông chữ, màu sắc, độ đậm nhạt của chữ, v.v. Các cột và hàng có các thuộc tính cho phép bạn chỉ định cách con của chúng được căn chỉnh theo chiều dọc hoặc chiều ngang và bao nhiêu không gian mà chúng nên chiếm.
Bố cục một widget
Làm thế nào để bạn bố cục một widget duy nhất trong Flutter? Phần này sẽ hướng dẫn bạn cách tạo và hiển thị một widget đơn giản. Nó cũng hiển thị toàn bộ code cho một ứng dụng Hello World đơn giản.
Trong Flutter ta chỉ cần vài bước để đưa văn bản, biểu tượng hoặc hình ảnh lên màn hình.
1. Chọn một widget bố cục
Chọn từ nhiều widget bố cục khác nhau dựa trên cách bạn muốn căn chỉnh hoặc hạn chế widget hiển thị, vì những đặc điểm này thường được chuyển cho widget con được chứa.
Ví dụ dưới đây sử dụng Center để căn giữa nội dung của nó theo chiều ngang và chiều dọc.
2. Tạo một widget hiển thị
Ví dụ: tạo một widget Text:
Text('Hello World'),
Tạo một widget Image:
Image.asset( 'images/img.jpg', fit: BoxFit.cover, ),
Tạo một widget Icon:
Icon( Icons.star, color: Colors.red[500], ),
3. Thêm widget hiển thị vào widget bố cục
Tất cả các widget bố cục đều có một trong những điều sau:
- Thuộc tính
child
nếu chúng có có một widget con, ví dụ:Center
hoặcContainer
- Thuộc tính
children
nếu chúng có một danh sách các widget con, ví dụ,Row
,Column
,ListView
, hoặcStack
.
Thêm widget Text
vào widget Center
:
Center( child: Text('Hello World'), ),
4. Thêm widget bố cục vào trang
Bản thân ứng dụng Flutter là một widget và hầu hết các widget đều có phương thức build(). Việc tạo và trả về một widget trong phương thức build()
của ứng dụng sẽ hiển thị widget đó.
Ứng dụng Material
Đối với ứng dụng Material
thì bạn có thể sử dụng widget Scaffold; nó cung cấp một biểu ngữ, màu nền mặc định và có API để thêm các drawer, snack bar, và các bottom sheet. Sau đó, bạn có thể thêm widget Center
trực tiếp vào thuộc tính body
cho trang chủ.
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter layout demo', home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Center( child: Text('Hello World'), ), ), ); } }
Lưu ý: Thư viện Material thực thi các widget cho phép các nguyên tắc thiết kế Material. Khi thiết kế giao diện người dùng, bạn có thể sử dụng độc quyền các widget từ thư viện widget tiêu chuẩn hoặc bạn có thể sử dụng các widget từ thư viện Material. Bạn có thể kết hợp các widget từ cả hai thư viện, bạn có thể tùy chỉnh các widget hiện có hoặc bạn có thể xây dựng bộ widget tùy chỉnh của riêng mình.
Ứng dụng Non-Material
Đối với ứng dụng Non-Material thì bạn có thể thêm widget Center
vào phương thức build()
của ứng dụng:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration(color: Colors.white), child: Center( child: Text( 'Hello World', textDirection: TextDirection.ltr, style: TextStyle( fontSize: 32, color: Colors.black87, ), ), ), ); } }
Theo mặc định, ứng dụng Non-Material không bao gồm màu AppBar
, tiêu đề hoặc màu nền. Nếu bạn muốn có các tính năng này trong một ứng dụng Non-Material, bạn phải tự xây dựng chúng. Ứng dụng này thay đổi màu nền thành màu trắng và văn bản thành màu xám đậm để bắt chước ứng dụng Material.
Khi bạn chạy ứng dụng ở trên, bạn sẽ thấy kết quả là Hello World.
Mã nguồn ứng dụng:
Bố cục nhiều widget theo chiều dọc và chiều ngang
Một trong những kiểu bố cục phổ biến nhất là sắp xếp các widget theo chiều dọc hoặc chiều ngang. Bạn có thể sử dụng widget Row
để sắp xếp các widget theo chiều ngang và widget Column
để sắp xếp các widget theo chiều dọc.
Vấn đề ở đây là gì?
Row
vàColumn
là hai trong số các mẫu bố cục được sử dụng phổ biến nhất.Row
vàColumn
đều có một danh sách các widget con.- Mỗi widget con có thể là một
Row
,Column
hoặc widget phức tạp khác. - Bạn có thể chỉ định cách một
Row
hoặcColumn
căn chỉnh các con của nó, theo cả chiều dọc và chiều ngang. - Bạn có thể kéo dài hoặc hạn chế các widget con cụ thể.
- Bạn có thể chỉ định cách các widget con sử dụng không gian có sẵn của '
Row
hoặcColumn
'.
Để tạo một hàng hoặc cột trong Flutter, bạn thêm danh sách các widget con vào một widget Row hoặc widget Column. Đổi lại, bản thân mỗi con có thể là một hàng hoặc cột, v.v. Ví dụ sau đây cho thấy cách có thể lồng các hàng hoặc cột vào bên trong các hàng hoặc cột.
Bố cục này được tổ chức như một Row
. Hàng sẽ chứa hai con: một cột ở bên trái và một hình ảnh ở bên phải:
Cây widget con của cột bên trái tổ chức các hàng và cột.
Bạn sẽ triển khai một số mã bố cục của Pavlova trong Lồng các hàng và cột.
Lưu ý:
Row
vàColumn
là các widget nguyên thủy cơ bản cho bố cục ngang và dọc - các widget cấp thấp này cho phép tùy chỉnh tối đa. Flutter cũng cung cấp các widget chuyên biệt, cấp cao hơn có thể đủ cho nhu cầu của bạn. Ví dụ: thay vìRow
bạn có thể thích ListTile, một widget con dễ sử dụng với các thuộc tính cho các biểu tượng đầu và cuối, và tối đa 3 dòng văn bản. Thay vì Column, bạn có thể thích ListView, một bố cục giống như cột tự động cuộn nếu nội dung của nó quá dài để phù hợp với không gian có sẵn. Để biết thêm thông tin, hãy xem Các widget bố cục chung.
Căn chỉnh widget
Bạn kiểm soát cách một hàng hoặc cột sắp xếp con của nó bằng cách sử dụng thuộc tính mainAxisAlignment
và crossAxisAlignment
. Đối với một hàng, trục chính chạy theo chiều ngang và trục chéo chạy theo chiều dọc. Đối với một cột, trục chính chạy theo chiều dọc và trục chéo chạy theo chiều ngang.
Các lớp MainAxisAlignment và CrossAxisAlignment cung cấp nhiều hằng số khác nhau để kiểm soát sự liên kết.
Lưu ý: Khi bạn thêm hình ảnh vào dự án của mình, bạn cần cập nhật file
pubspec.yaml
để truy cập chúng - ví dụ này sử dụngImage.asset
để hiển thị hình ảnh. Để biết thêm thông tin, hãy xem file ubspec.yaml của ví dụ này hoặc bài viết Thêm nội dung và hình ảnh. Bạn không cần phải làm điều này nếu bạn đang tham khảo hình ảnh trực tuyến bằng cách sử dụngImage.network
.
Trong ví dụ sau, mỗi ảnh có chiều rộng 100 pixel. Hộp kết xuất (trong trường hợp này là toàn bộ màn hình) rộng hơn 300 pixel, vì vậy việc đặt căn chỉnh trục chính để spaceEvenly
chia đều không gian ngang trống giữa, trước và sau mỗi hình ảnh.
Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Image.asset('images/pic1.jpg'), Image.asset('images/pic2.jpg'), Image.asset('images/pic3.jpg'), ], );
Nguồn ứng dụng: row_column
Các cột hoạt động giống như các hàng. Ví dụ sau đây cho thấy một cột gồm 3 hình ảnh, mỗi hình ảnh cao 100 pixel. Chiều cao của hộp kết xuất (trong trường hợp này là toàn bộ màn hình) là hơn 300 pixel, do đó, thiết lập căn chỉnh trục chính để spaceEvenly
chia đều không gian dọc vùng trống ở giữa, trên và dưới mỗi hình ảnh.
Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Image.asset('images/pic1.jpg'), Image.asset('images/pic2.jpg'), Image.asset('images/pic3.jpg'), ], );
Nguồn ứng dụng: row_column
Kích thước widget
Khi bố cục quá lớn để vừa với một thiết bị, một hình sọc màu vàng đen sẽ xuất hiện dọc theo cạnh bị ảnh hưởng. Dưới đây là một ví dụ về một hàng quá rộng:
Các widget có thể được định kích thước để vừa với một hàng hoặc cột bằng cách sử dụng widget Expanded. Để sửa ví dụ trên trong đó hàng hình ảnh quá rộng đối với hộp kết xuất của nó, hãy bao ngoài mỗi hình ảnh bằng một widget Expanded
.
Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Image.asset('images/pic1.jpg'), ), Expanded( child: Image.asset('images/pic2.jpg'), ), Expanded( child: Image.asset('images/pic3.jpg'), ), ], );
Nguồn ứng dụng: định cỡ
Nếu bạn muốn một widget chiếm dung lượng gấp đôi so với các widget cạnh nó thì bạn có thể sử dụng thuộc tính flex
của widget Expanded
, nó chứa một số nguyên xác định hệ số linh hoạt cho một widget. Hệ số flex mặc định là 1. Đoạn mã sau đặt hệ số flex của hình ảnh giữa thành 2:
Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Image.asset('images/pic1.jpg'), ), Expanded( flex: 2, child: Image.asset('images/pic2.jpg'), ), Expanded( child: Image.asset('images/pic3.jpg'), ), ], );
Nguồn ứng dụng: định cỡ
Đóng gói widget
Theo mặc định, một hàng hoặc cột chiếm càng nhiều không gian dọc theo trục chính của nó càng tốt, nhưng nếu bạn muốn đóng gói các con lại gần nhau, hãy đặt mainAxisSize
thành MainAxisSize.min
. Ví dụ sau sử dụng thuộc tính này để đóng gói các biểu tượng ngôi sao lại với nhau.
Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.star, color: Colors.green[500]), Icon(Icons.star, color: Colors.green[500]), Icon(Icons.star, color: Colors.green[500]), Icon(Icons.star, color: Colors.black), Icon(Icons.star, color: Colors.black), ], )
Nguồn ứng dụng: pavlova
Lồng các hàng và cột
Bố cục framework cho phép bạn lồng các hàng và cột vào bên trong các hàng và cột sâu tùy thích. Hãy xem đoạn mã sau cho phần được phác thảo của bố cục sau:
Phần được phác thảo được thực hiện thành hai hàng. Hàng xếp hạng chứa năm sao và số lượng đánh giá. Hàng biểu tượng chứa ba cột biểu tượng và văn bản.
Cây tiện ích con cho hàng xếp hạng:
Biến ratings
tạo ra một hàng chứa một hàng nhỏ hơn của biểu tượng 5 sao, và văn bản:
var stars = Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.star, color: Colors.green[500]), Icon(Icons.star, color: Colors.green[500]), Icon(Icons.star, color: Colors.green[500]), Icon(Icons.star, color: Colors.black), Icon(Icons.star, color: Colors.black), ], ); final ratings = Container( padding: EdgeInsets.all(20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ stars, Text( '170 Reviews', style: TextStyle( color: Colors.black, fontWeight: FontWeight.w800, fontFamily: 'Roboto', letterSpacing: 0.5, fontSize: 20, ), ), ], ), );
Mẹo: Để giảm thiểu sự nhầm lẫn trực quan có thể do mã bố cục lồng nhau nhiều, hãy triển khai các phần của giao diện người dùng trong các biến và hàm.
Hàng biểu tượng nằm bên dưới hàng xếp hạng chứa 3 cột, mỗi cột chứa một biểu tượng và hai dòng văn bản, như bạn có thể thấy trong cây tiện ích con của nó như sau:
Biến iconList
định nghĩa các hàng biểu tượng:
final descTextStyle = TextStyle( color: Colors.black, fontWeight: FontWeight.w800, fontFamily: 'Roboto', letterSpacing: 0.5, fontSize: 18, height: 2, ); // DefaultTextStyle.merge() cho phép bạn tạo một kiểu text mặc định // được thừa kế bởi con và các cháu của nó. final iconList = DefaultTextStyle.merge( style: descTextStyle, child: Container( padding: EdgeInsets.all(20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Column( children: [ Icon(Icons.kitchen, color: Colors.green[500]), Text('PREP:'), Text('25 min'), ], ), Column( children: [ Icon(Icons.timer, color: Colors.green[500]), Text('COOK:'), Text('1 hr'), ], ), Column( children: [ Icon(Icons.restaurant, color: Colors.green[500]), Text('FEEDS:'), Text('4-6'), ], ), ], ), ), );
Biến leftColumn
có chứa các xếp hạng và các biểu tượng hàng, cũng như các tiêu đề và văn bản mô tả Pavlova:
final leftColumn = Container( padding: EdgeInsets.fromLTRB(20, 30, 20, 20), child: Column( children: [ titleText, subTitle, ratings, iconList, ], ), );
Cột bên trái được đặt trong một Container
để hạn chế chiều rộng của nó. Cuối cùng, giao diện người dùng được xây dựng với toàn bộ hàng (chứa cột bên trái và hình ảnh) bên trong một Card
.
Các hình ảnh Pavlova là từ Pixabay. Bạn có thể nhúng hình ảnh từ mạng bằng cách sử dụng Image.network()
, nhưng ở ví dụ này hình ảnh được lưu vào thư mục hình ảnh trong dự án, được thêm vào file pubspec và được truy cập bằng cách sử dụng Images.asset()
. Để biết thêm thông tin, hãy xem Thêm nội dung và hình ảnh.
body: Center( child: Container( margin: EdgeInsets.fromLTRB(0, 40, 0, 30), height: 600, child: Card( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 440, child: leftColumn, ), mainImage, ], ), ), ), ),
Mẹo: Ví dụ về Pavlova chạy tốt nhất theo chiều ngang trên một thiết bị chẳng hạn như máy tính bảng. Nếu bạn đang chạy ví dụ này trong trình mô phỏng iOS, bạn có thể chọn một thiết bị khác bằng menu Hardware> Device. Đối với ví dụ này ta sử dụng iPad Pro. Bạn có thể thay đổi hướng của nó sang chế độ ngang bằng cách sử dụng Hardware> Rotate. Bạn cũng có thể thay đổi kích thước của cửa sổ trình mô phỏng (mà không thay đổi số lượng pixel hợp lý) bằng cách sử dụng Window> Scale.
Nguồn ứng dụng: pavlova
Các widget bố cục phổ biến
Flutter có một thư viện phong phú các widget bố cục. Dưới đây là một số widget được sử dụng phổ biến nhất. Mục đích là giúp bạn bắt đầu và hoạt động nhanh nhất có thể, thay vì khiến bạn choáng ngợp với một danh sách đầy đủ các widget. Để biết thông tin về các tiện ích có sẵn khác, hãy tham khảo danh mục Tiện ích hoặc sử dụng hộp Tìm kiếm trong tài liệu tham khảo API. Ngoài ra, các trang tiện ích con trong tài liệu API thường đưa ra đề xuất về các tiện ích con tương tự có thể phù hợp hơn với nhu cầu của bạn.
Các widget sau đây thuộc hai loại: widget tiêu chuẩn từ thư viện widget và các widget chuyên dụng từ thư viện Material. Bất kỳ ứng dụng nào cũng có thể sử dụng thư viện widget nhưng chỉ ứng dụng Material mới có thể sử dụng thư viện Material Components.
Widget tiêu chuẩn
- Container: Thêm phần đệm, lề, đường viền, màu nền hoặc các trang trí khác vào tiện ích con.
- GridView: Đưa các widget ra dưới dạng lưới có thể cuộn.
- ListView: Đưa các widget ra dưới dạng danh sách có thể cuộn.
- Stack: Đặt chồng một tiện ích con lên trên một tiện ích con khác.
Widget Material
- Card: Sắp xếp thông tin liên quan vào một hộp có các góc tròn và bóng đổ.
- ListTile: Sắp xếp tối đa 3 dòng văn bản và các biểu tượng đầu và cuối tùy chọn thành một hàng.
Container
Nhiều bố cục sử dụng tự do các Container để tách các tiện ích con bằng cách sử dụng đệm hoặc để thêm đường viền hoặc lề. Bạn có thể thay đổi nền của thiết bị bằng cách đặt toàn bộ bố cục vào một Container
và thay đổi màu nền hoặc hình ảnh của nó.
Tổng quan Container
- Thêm đệm (margin), lề (padding), đường viền (border)
- Thay đổi màu nền hoặc hình ảnh
- Chứa một tiện ích con duy nhất, nhưng tiện ích con đó có thể là Hàng, Cột hoặc thậm chí là gốc của cây tiện ích con
Ví dụ về Container
Bố cục dưới đây bao gồm một cột có hai hàng, mỗi hàng chứa 2 hình ảnh. Một Container được sử dụng để thay đổi màu nền của cột thành màu xám nhạt hơn.
Widget _buildImageColumn() => Container( decoration: BoxDecoration( color: Colors.black26, ), child: Column( children: [ _buildImageRow(1), _buildImageRow(3), ], ), );
Container
cũng được sử dụng để thêm đường viền và lề tròn cho mỗi hình ảnh như sau:
Widget _buildDecoratedImage(int imageIndex) => Expanded( child: Container( decoration: BoxDecoration( border: Border.all(width: 10, color: Colors.black38), borderRadius: const BorderRadius.all(const Radius.circular(8)), ), margin: const EdgeInsets.all(4), child: Image.asset('images/pic$imageIndex.jpg'), ), ); Widget _buildImageRow(int imageIndex) => Row( children: [ _buildDecoratedImage(imageIndex), _buildDecoratedImage(imageIndex + 1), ], );
Bạn có thể tìm thêm các ví dụ về Container
trong hướng dẫn và Thư viện Flutter (ứng dụng đang chạy, repo).
Nguồn ứng dụng: container
GridView (Chế độ hiển thị theo ô)
Sử dụng GridView để sắp xếp các widget dưới dạng danh sách hai chiều. GridView
cung cấp hai danh sách được tạo sẵn hoặc bạn có thể tạo lưới tùy chỉnh của riêng mình. Khi GridView
phát hiện thấy nội dung của nó quá dài để vừa với hộp kết xuất, nó sẽ tự động cuộn.
Tổng quan GridView
- Đặt các widget trong một lưới
- Phát hiện khi nội dung cột vượt quá hộp hiển thị và tự động cung cấp chức năng cuộn
- Tạo lưới tùy chỉnh của riêng bạn hoặc sử dụng một trong các lưới được cung cấp:
GridView.count
cho phép bạn chỉ định số lượng cộtGridView.extent
cho phép bạn chỉ định chiều rộng pixel tối đa của ô
Lưu ý: Khi hiển thị danh sách hai chiều, trong đó điều quan trọng là hàng và cột mà ô chiếm (ví dụ: đó là mục nhập trong cột "calo" cho hàng "bơ"), hãy sử dụng Table hoặc DataTable.
Ví dụ về GridView
Sử dụng GridView.extent
để tạo lưới với các ô có chiều rộng tối đa 150 pixel.
Nguồn ứng dụng: grid_and_list
Sử dụng GridView.count
để tạo lưới rộng 2 ô ở chế độ dọc và rộng 3 ô ở chế độ ngang. Các tiêu đề được tạo bằng cách đặt thuộc tính footer
cho mỗi GridTile.
Code Dart: grid_list_demo.dart từ Thư viện Flutter
Widget _buildGrid() => GridView.extent( maxCrossAxisExtent: 150, padding: const EdgeInsets.all(4), mainAxisSpacing: 4, crossAxisSpacing: 4, children: _buildGridTileList(30)); // Ảnh được lưu với tên pic0.jpg, pic1.jpg...pic29.jpg. // Hàm tạo List.generate() cho phép ta dễ dàng tạo // danh sách khi các đối tượng có kiểu đặt tên dễ đoán. List<Container> _buildGridTileList(int count) => List.generate( count, (i) => Container(child: Image.asset('images/pic$i.jpg')) );
ListView
ListView, một tiện ích giống như cột, tự động cung cấp khả năng cuộn khi nội dung của nó quá dài so với hộp kết xuất của nó.
Tổng quan ListView
- Column dùng để sắp xếp danh sách các hộp
- Có thể được bố trí theo chiều ngang hoặc chiều dọc
- Phát hiện khi nào nội dung của nó không phù hợp và cung cấp khả năng cuộn
- Ít cấu hình hơn
Column
, nhưng dễ sử dụng hơn và hỗ trợ cuộn
Ví dụ về ListView
Sử dụng ListView
để hiển thị danh sách các doanh nghiệp sử dụng ListTile
. A Divider
ngăn cách các rạp hát với các nhà hàng.
Nguồn ứng dụng: grid_and_list
Sử dụng ListView
để hiển thị Colors từ bảng Material Design cho một họ màu cụ thể.
Code Dart: Colors_demo.dart từ Thư viện Flutter
Widget _buildList() => ListView( children: [ _tile('CineArts at the Empire', '85 W Portal Ave', Icons.theaters), _tile('The Castro Theater', '429 Castro St', Icons.theaters), _tile('Alamo Drafthouse Cinema', '2550 Mission St', Icons.theaters), _tile('Roxie Theater', '3117 16th St', Icons.theaters), _tile('United Artists Stonestown Twin', '501 Buckingham Way', Icons.theaters), _tile('AMC Metreon 16', '135 4th St #3000', Icons.theaters), Divider(), _tile('K\'s Kitchen', '757 Monterey Blvd', Icons.restaurant), _tile('Emmy\'s Restaurant', '1923 Ocean Ave', Icons.restaurant), _tile( 'Chaiya Thai Restaurant', '272 Claremont Blvd', Icons.restaurant), _tile('La Ciccia', '291 30th St', Icons.restaurant), ], ); ListTile _tile(String title, String subtitle, IconData icon) => ListTile( title: Text( title, style: TextStyle( fontWeight: FontWeight.w500, fontSize: 20, ) ), subtitle: Text(subtitle), leading: Icon( icon, color: Colors.blue[500], ), );
Stack
Sử dụng Stack để sắp xếp các widget trên cùng một widget cơ sở - thường là một hình ảnh. Các widget có thể chồng lên hoàn toàn hoặc một phần widget cơ sở.
Tổng quan Ngăn xếp
- Sử dụng cho các widget chồng lên một widget khác
- Tiện ích đầu tiên trong danh sách con là tiện ích cơ sở; các con tiếp theo được phủ lên trên tiện ích cơ sở đó
- Nội dung của Stack không thể được cuộn
- Bạn có thể chọn để kẹp các con vượt quá hộp kết xuất
Ví dụ về Stack
Sử dụng Stack
để phủ một Container
(hiển thị Text
trên nền đen mờ) lên trên một CircleAvatar
. Stack
bù trừ văn bản bằng cách sử dụng thuộc tính alignment
và Alignment
s.
Nguồn ứng dụng: card_and_stack
Sử dụng Stack
để phủ một gradient lên trên cùng của hình ảnh. Gradient đảm bảo rằng các biểu tượng của thanh công cụ khác biệt với hình ảnh.
Code Dart: contacts_demo.dart từ Gallery Flutter
Card
Card từ thư viện Material, chứa các thông tin liên quan và có thể được tạo từ hầu hết các widget, nhưng thường được sử dụng với ListTile. Card có một con duy nhất, nhưng con của nó có thể là một cột, hàng, danh sách, lưới hoặc tiện ích con khác hỗ trợ nhiều con. Theo mặc định, Card
thu nhỏ kích thước của nó thành 0 x 0 pixel. Bạn có thể sử dụng SizedBox để giới hạn kích thước của thẻ.
Trong Flutter, Card
có các góc hơi tròn và bóng đổ, tạo hiệu ứng 3D. Thay đổi thuộc tính elevation
của Card
cho phép bạn kiểm soát các hiệu ứng đổ bóng. Ví dụ, đặt độ cao lên 24, trực quan sẽ nâng cao Card
hơn khỏi bề mặt và làm cho bóng trở nên phân tán hơn. Để biết danh sách các giá trị độ cao được hỗ trợ, hãy xem Độ cao trong nguyên tắc Material. Việc chỉ định một giá trị không được hỗ trợ sẽ vô hiệu hóa hoàn toàn bóng đổ.
Tổng quan Card
- Triển khai card Material
- Được sử dụng để trình bày các thông tin liên quan
- Chấp nhận một con duy nhất, nhưng con đó có thể là một
Row
,Column
hoặc widget khác chứa một danh sách các con - Được hiển thị với các góc tròn và bóng đổ
- Nội dung của Card không thể được cuộn
- Từ thư viện Material
Ví dụ về Card
Card
chứa 3 ListTile và có kích thước bằng cách gói nó bằng một SizedBox
. Divider
ngăn cách ListTile thứ nhất và ListTile thứ hai.
Nguồn ứng dụng: card_and_stack
Card
chứa hình ảnh và văn bản.
Code Dart: card_demo.dart từ Thư viện Flutter
Widget _buildCard() => SizedBox( height: 210, child: Card( child: Column( children: [ ListTile( title: Text('1625 Main Street', style: TextStyle(fontWeight: FontWeight.w500)), subtitle: Text('My City, CA 99984'), leading: Icon( Icons.restaurant_menu, color: Colors.blue[500], ), ), Divider(), ListTile( title: Text('(408) 555-1212', style: TextStyle(fontWeight: FontWeight.w500)), leading: Icon( Icons.contact_phone, color: Colors.blue[500], ), ), ListTile( title: Text('costa@example.com'), leading: Icon( Icons.contact_mail, color: Colors.blue[500], ), ), ], ), ), );
ListTile
Sử dụng ListTile, là widget hàng chuyên biệt từ thư viện Material để dễ dàng tạo một hàng có chứa tối đa 3 dòng văn bản và các biểu tượng đầu và cuối tùy chọn. ListTile
được sử dụng phổ biến nhất trong Card hoặc ListView, nhưng có thể được sử dụng ở những nơi khác.
Tổng quan ListTile
- Một hàng chuyên biệt chứa tối đa 3 dòng văn bản và các biểu tượng tùy chọn
- Ít cấu hình hơn
Row
, nhưng dễ sử dụng hơn - Từ thư viện Material
Ví dụ về ListTile
Card
chứa 3 ListTile
.
Nguồn ứng dụng: card_and_stack
ListTile
dùng để liệt kê 3 loại nút thả xuống.
Code Dart: button_demo.dart từ Thư viện Flutter
Ràng buộc
Để hiểu đầy đủ về hệ thống bố cục của Flutter, bạn cần tìm hiểu cách Flutter định vị và kích thước các thành phần trong một bố cục. Để biết thêm thông tin, hãy xem Hiểu về các ràng buộc.
Các nguồn tham khảo
Các tài nguyên sau đây có thể hữu ích khi viết mã bố cục.
Tìm hiểu cách xây dựng bố cục.
Mô tả nhiều tiện ích có sẵn trong Flutter.
Đối với những người quen thuộc với lập trình web, trang này ánh xạ chức năng HTML / CSS với các tính năng của Flutter.
- Ứng dụng đang chạy Flutter Gallery, repo
Ứng dụng demo giới thiệu nhiều tiện ích Material Design và các tính năng Flutter khác.
Tài liệu tham khảo cho tất cả các thư viện Flutter.
Thảo luận về cách các widget bị hạn chế bởi các hộp kết xuất của chúng.
Giải thích cách thêm hình ảnh và các nội dung khác vào gói ứng dụng của bạn.
Trải nghiệm của một người khi viết ứng dụng Flutter đầu tiên của mình.