Facebook Pixel

Tìm hiểu Stack và IndexedStack trong Flutter

28 Jan, 2022

Chau Le

Author

Khám phá Stack widget và IndexedStack widget và công dụng của chúng. Trong bài viết này, chúng ta sẽ xem xét Stack widget và các loại của nó.

Tìm hiểu Stack và IndexedStack trong Flutter

Mục Lục

Trong bài viết này, chúng ta sẽ xem xét Stackwidget và các loại của nó.

Giới thiệu

Stackwidget 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:

  1. Stack
  2. IndexedStack

Hãy cùng khám phá cách sử dụng Stack.

Stack

Stackwidget 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.

Dart
Stack(
  children: <Widget>[
    BottomWidget(),
    MiddleWidget(),
    TopWidget(),
  ],
),

Kích thước củaStacklà 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ỏ:

Dart
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ằngAlignwidget hoặcPositionedwidget.

Alignwidget 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.Positionedwidget kết hợp hai điều này và cho phép chúng ta giữ mộtPositionedwidget thay vìAlignPadding.

Chúng ta sẽ thay đổi ví dụ của mình để sử dụngAlignPositioned. Hãy wrap một cách đơn giản các container của chúng ta trongAlignvà sau đó làPositionedwidget.

Lưu ý:Positionedphả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:

Dart
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ớiAlignhoặcPositionedđể kiểm soát chi tiết hơn.

Positionedcó 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.

Dart
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 đó,Positionedlà một widget tốt hơn để sử dụng trongStackhơnAlign+Paddingnhư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ó.

Dart
IndexedStack(
  index: 1,
  children: <Widget>[
    BottomWidget(),
    MidWidget(),
    TopWidget(),
  ],
)

Nó nhận các children giống như mộtStackthô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ụ:

Dart
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ớiIndexedStackvà cho nóindex0, nó sẽ hiển thị child dưới cùng.

Hai children trên không được hiển thị vìindexlà 0.

Hai children trên không được hiển thị vìindexlà 0.
Lưu ý: Kích thước vẫn là kích thước của element lớn nhất.
IndexedStackcũng trực tiếp nhận một tham sốalignmentvà căn chỉnh tất cả các children cho phù hợp.

Dart
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

Dart
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ó

Dart
Container(
  decoration: BoxDecoration(
    image: DecorationImage(
      image: AssetImage('images/new_york.jpg'),
      fit: BoxFit.fitHeight,
    ),
  ),
),

Step 3) Thêm card

Dart
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í

Dart
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à:

Dart
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.

Bài viết liên quan

Lập trình backend expressjs

xây dựng hệ thống microservices
  • Kiến trúc Hexagonal và ứng dụngal font-
  • TypeScript: OOP và nguyên lý SOLIDal font-
  • Event-Driven Architecture, Queue & PubSubal font-
  • Basic scalable System Designal font-

Đăng ký nhận thông báo

Đừng bỏ lỡ những bài viết thú vị từ 200Lab