Trang chủ Kiến Thức Công Nghệ Tìm hiểu Stack và IndexedStack trong Flutter
Công Nghệ

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

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

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 cùng chuyên mục
Tối ưu ứng dụng với cấu trúc dữ liệu cơ bản và bitwise
Công Nghệ

Tối ưu ứng dụng với cấu trúc dữ liệu cơ bản và bitwise

Trong bài viết này, 200Lab sẽ chia sẻ những trường hợp dễ...

Công Nghệ

So sánh Flutter vs React Native: Framework nào đáng học năm 2021

Điểm chung của Flutter, React Native đều là Cross-platform Mobile, build native...

HTTP/2 là gì? So sánh HTTP/2 và HTTP/1
Công Nghệ

HTTP/2 là gì? So sánh HTTP/2 và HTTP/1

Từ khi Internet ra đời, sự phát triển về các giao thức...

Upload File từ Frontend đến Backend mà rất nhiều bạn vẫn đang làm sai!!
Công Nghệ

Upload File từ Frontend đến Backend mà rất nhiều bạn vẫn đang làm sai!!

1. Client encode file (base64) rồi gởi về backend 200Lab đã từng...

Công Nghệ

React Native – Hướng dẫn làm việc với Polyline và Animated-Polyline trên Map

Vẽ đường đi trên bản đồ là một nghiệp vụ vô cùng...

Công Nghệ

Hybrid App và Native App: Những khác biệt to lớn

Bất cứ khi nào một công ty quyết định làm ứng dụng...

Web/System Architecture 101 – Kiến trúc web/hệ thống cơ bản cho người mới
Công Nghệ

Web/System Architecture 101 – Kiến trúc web/hệ thống cơ bản cho người mới

Đây là một kiến trúc cơ bản mà bất kì một người...

Công Nghệ

Tư duy kiến trúc thông qua các trò chơi mà rất nhiều bạn không biết

Tư duy kiến trúc là gì? Tư duy kiến trúc có thể...