, May 25, 2022

0 kết quả được tìm thấy

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

  • Đăng bởi  Chau Le
  •  Jan 29, 2022

  •   8 min reads
Tìm hiểu Stack và IndexedStack trong Flutter

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.

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

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:

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.

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

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

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.

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.

Bài viết liên quan

Fix lỗi Flutter 3 không thể build app trên iOS

Cách fix lỗi Flutter 3 không thể build và run được app trên iOS với video hướng dẫn chia tiết...

Fix lỗi Flutter 3 không thể build app trên iOS
Flutter Coding UI Speed Code

Nhận bản UI siêu đẹp nhưng làm sao để phân tích rồi code ra một cách chính xác nhất? Series này 200Lab sẽ cho bạn một góc nhìn thực tế về quá trình code UI cho app Movie Ticket....

Flutter Coding UI Speed Code
Flutter 3 - Những cập nhật mới có gì hot

Bài viết này cung cấp cho bạn những thông tin cập nhật mới nhất của Flutter 3, giúp bạn có cái nhìn tổng quan về các thay đổi và tính năng bổ ích...

Flutter 3 - Những cập nhật mới có gì hot
Mọi thứ bạn cần biết về Route Transition của Flutter

Chúng ta cũng có thể kết hợp nhiều transition để tạo ra thứ gì đó tuyệt vời như scale và rotate cùng một lúc....

Mọi thứ bạn cần biết về Route Transition của Flutter
Hướng dẫn custom RenderObject của riêng bạn

Khi "khám phá" source code Flutter, bạn sẽ phát hiện ra rằng phần lớn các widget không sử dụng composition hay CustomPaint. Thay vào đó, chúng sử dụng RenderObject...

Hướng dẫn custom RenderObject của riêng bạn
You've successfully subscribed to 200Lab Blog
Great! Next, complete checkout for full access to 200Lab Blog
Xin chào mừng bạn đã quay trở lại
OK! Tài khoản của bạn đã kích hoạt thành công.
Success! Your billing info is updated.
Billing info update failed.
Your link has expired.