Trong bài viết này, chúng ta sẽ xem xét Stack
widget và các loại của nó.
Giới thiệu
Stack
widget cho phép chúng ta tạo nhiều widget chồng lên nhau. Điều này không chỉ cho phép các thiết kế có thể tùy chỉnh nhiều kiểu mà còn có một số hình ảnh động thực sự thú vị.
Có hai loại Stack chính:
Stack
IndexedStack
Hãy cùng khám phá cách sử dụng Stack.
Stack
Stack
widget cho phép chúng ta xếp chồng nhiều layer lên nhau. Widget có nhiều children và sắp xếp chúng từ dưới lên trên. Vì vậy, mục đầu tiên là dưới cùng và cuối cùng là trên cùng.
Stack(
children: <Widget>[
BottomWidget(),
MiddleWidget(),
TopWidget(),
],
),
Kích thước củaStack
là kích thước của member lớn nhất trong layer. Vì vậy, nếu layer dưới cùng bao phủ toàn bộ màn hình thì kích thước của Stack là toàn màn hình hoàn chỉnh.
Mỗi member trong Stack cần được định vị hoặc căn chỉnh toạ độ, nếu không nó sẽ kết thúc ở góc trên cùng bên trái theo mặc định.
Ví dụ, hãy lấy ba container có kích thước thu nhỏ:
Stack(
children: <Widget>[
// Max Size
Container(
color: Colors.green,
),
Container(
color: Colors.blue,
height: 300.0,
width: 300.0,
),
Container(
color: Colors.pink,
height: 150.0,
width: 150.0,
)
],
),
Điều này mang lại cho chúng ta:
Nếu bạn để ý, các container nhỏ hơn có nhiều diện tích hơn để chuyển đến và do đó mặc định ở trên cùng bên trái. Để thay đổi điều này, bạn có thể căn chỉnh hoặc định vị widget của mình bằngAlign
widget hoặcPositioned
widget.
Align
widget thường đưa widget đến các vị trí cao nhất. Vậy nên ví dụ: nếu chúng ta nhập trên cùng bên phải, chúng ta cần thêm padding bổ sung để giữ cho nó gọn gàng và ngăn nắp.Positioned
widget kết hợp hai điều này và cho phép chúng ta giữ mộtPositioned
widget thay vìAlign
vàPadding
.
Chúng ta sẽ thay đổi ví dụ của mình để sử dụngAlign
và Positioned
. Hãy wrap một cách đơn giản các container của chúng ta trongAlign
và sau đó làPositioned
widget.
Lưu ý:Positioned
phải là child củaStack
. Không thể có một widget khác ở giữa Stack và widget.
Để căn chỉnh một cách đơn giản widget:
Align(
alignment: Alignment.topRight,
child: Container(
color: Colors.pink,
height: 150.0,
width: 150.0,
),
)
Ở đây chúng ta căn chỉnh nó ở trên cùng bên phải (top right). Thông thường, đây không phải là những gì chúng ta thực sự muốn vì chúng ta cần một số padding vào container từ các cạnh. Chúng ta có thể sử dụng padding vớiAlign
hoặcPositioned
để kiểm soát chi tiết hơn.
Positioned
có nhiều loại, chúng ta sẽ tập trung vào loại mặc định.
Positioned
chấp nhận các giá trị từ cả bốn phía, cho child biết nó phải cách xa cạnh tương ứng đó bao xa. Nếu không có giá trị nào được đưa ra, nó sẽ thu hẹp đến kích thước thấp nhất có thể.
Tại đây, chúng ta đưa ra một giá trị ở trên cùng và bên phải. Trên thực tế, điều này có nghĩa là child sẽ cách phía trên và bên phải 40.0 và không có constraint nào khác ở các phía khác. Do đó, nó cũng được căn chỉnh về phía trên và bên phải theo định nghĩa.
Positioned(
right: 40.0,
top: 40.0,
child: Container(
color: Colors.pink,
height: 150.0,
width: 150.0,
),
)
Điều này mang lại cho chúng ta:
Do đó,Positioned
là một widget tốt hơn để sử dụng trongStack
hơnAlign
+Padding
nhưng không có tác hại thực sự nào cả.
Ngoài ra còn có các loại Positioned khác. Một vài trong số đó là:
Positioned.fill()
Set top, right, bottom, left thành 0.0 theo mặc định trừ khi bị ghi đè. Do đó, nó lấp đầy màn hình theo mặc định vì khoảng cách từ cả bốn cạnh là 0.0.
Positioned.fromRect()
Tạo một Positioned object từ một Rect đã cho.
Trước khi chuyển sang tạo thứ gì đó với Stack, chúng ta hãy xem xét loại thứ hai.
IndexedStack
IndexedStack là một Stack mà chỉ một element được hiển thị tại một thời điểm bằng index của nó.
IndexedStack(
index: 1,
children: <Widget>[
BottomWidget(),
MidWidget(),
TopWidget(),
],
)
Nó nhận các children giống như mộtStack
thông thường nhưng ngược lại, nó chỉ hiển thị một child tại một thời điểm. Theo một cách nào đó, đó không phải là một stack và hơn thế nữa là một cách để dễ dàng chuyển đổi giữa các children khi bạn cần.
Hãy xem ví dụ:
IndexedStack(
index: 0,
children: <Widget>[
Container(
color: Colors.green,
),
Container(
alignment: Alignment.bottomLeft,
color: Colors.blue,
height: 300.0,
width: 300.0,
),
Container(
color: Colors.pink,
height: 150.0,
width: 150.0,
)
],
),
Khi chúng ta wrap các element giống nhau vớiIndexedStack
và cho nóindex
0, nó sẽ hiển thị child dưới cùng.
Hai children trên không được hiển thị vìindex
là 0.
Hai children trên không được hiển thị vìindex
là 0.
Lưu ý: Kích thước vẫn là kích thước của element lớn nhất.IndexedStack
cũng trực tiếp nhận một tham sốalignment
và căn chỉnh tất cả các children cho phù hợp.
IndexedStack(
index: 1,
children: <Widget>[
//Children
],
alignment: Alignment.topRight,
)
Hãy làm điều gì đó với Stack
Đây là một ví dụ tương đối đơn giản về việc chúng ta có thể sử dụng Stack. Một hình ảnh được phủ lên bởi một card được đặt ở tâm dưới cùng.
Bước 1) Thêm Stack
Stack(
children: <Widget>[
],
)
Bước 2) Thêm background
Ở đây, mình chỉ đang sử dụng một container có hình ảnh bên trong nó
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/new_york.jpg'),
fit: BoxFit.fitHeight,
),
),
),
Step 3) Thêm card
Card(
elevation: 8.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
"New York",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."),
),
],
),
),
Step 4) Đặt card vào đúng vị trí
Positioned(
bottom: 48.0,
left: 10.0,
right: 10.0,
child: Card(
elevation: 8.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
"New York",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."),
),
],
),
),
),
Và chúng ta đã hoàn thành!
Code cuối cùng là:
import 'package:flutter/material.dart';
class DemoPage extends StatefulWidget {
@override
_DemoPageState createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/new_york.jpg'),
fit: BoxFit.fitHeight,
),
),
),
Positioned(
bottom: 48.0,
left: 10.0,
right: 10.0,
child: Card(
elevation: 8.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
"New York",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."),
),
],
),
),
),
],
),
);
}
}
Một số thử nghiệm của mình với Stack
Stack ít nhiều phổ biến trong ứng dụng Flutter, nhưng mình đã cố gắng sử dụng chúng theo một vài cách khác nhau (Chủ yếu được kết hợp với Transform widget). Đây là một vài dự án của mình mà bạn có thể xem qua.
Tạo hộp 3D cho BottomNavigationBar
Các mục trong BottomNavigationBar được tạo bằng Stack widget và Transform widget.
Link: https://medium.com/flutter-community/flutter-challenge-3d-bottom-navigation-bar-48952a5fd996
Tạo Card stack cho Solitaire trong Flutter
Mỗi cột thẻ ở đây được tạo bằng một Stack.
Link: https://medium.com/flutter-community/creating-solitaire-in-flutter-946c34ef053c
Mình mong là bạn sẽ thích bài viết này.
Bài viết được lược dịch từ Deven Joshi.
Chau Le
Cực thích đồ ngọt như sữa, kem. Thích phiêu lưu mạo hiểm nhưng vì Covid mà vô tình trở thành người chia sẻ nội dung lập trình :))
follow me :
Bài viết liên quan
Tự học Dart: Các Dart Operators (toán tử) bạn cần biết
Sep 02, 2023 • 18 min read
Flutter cơ bản: Điều cần biết khi lập trình ứng dụng đầu tiên
Aug 23, 2023 • 13 min read
Dart là gì? Giới thiệu cơ bản về ngôn ngữ lập trình Dart
Aug 21, 2023 • 11 min read
Flutter là gì? Vì sao nên học công cụ lập trình Flutter?
Aug 19, 2023 • 11 min read
Flutter cơ bản: Widget Tree, Element Tree & Render Tree
Aug 19, 2023 • 10 min read
So sánh StatelessWidget và StatefulWidget
Jul 17, 2022 • 12 min read