[譯]在 Flutter 中如何設計線性佈局?

趙阿海發表於2019-09-22

原文作者:Burhanuddin Rashid,Google 認證 Android 開發者

原文連結:Flutter For Android Developers : How to design LinearLayout in Flutter.


這篇部落格是為那些想把現有的開發知識應用到 Flutter 的 Android 開發者寫的。在這篇文章裡,我們將會探索在 Flutter 中與 LinearLayout 對應的是什麼。

部落格系列

先決條件

這篇文章假設你已經在電腦上配置好了 Flutter 的執行環境並且能成功執行一個 Hello World 專案。如果你還沒有安裝 Flutter,你可以從這裡開始

Dart 是一門基於物件導向的語言,對一個 Android 開發者來說是很容易掌握的。

讓我們開始吧

如果你是一個 Android 開發者,我想你應該會在設計佈局時重度使用LinearLayout。對於不熟悉LinearLayout的人,我先從官方定義開始吧。

線性佈局就是一個把其他檢視元件水平排成一行或垂直排成一列的佈局。

線性佈局

有了上述定義和圖片演示,你就可以知道在 Flutter 中與 LinearLayout 相同的部件。沒錯,它們就是RowColumn。這兩個部件的行為幾乎和 Android 原生的 LinearLayout 一模一樣。Row 和 Column 在 Flutter 中也是被重度使用的部件。

注意:Row/Column 不會滾動。如果你有一些線性排列的控制元件並且希望在空間不夠時它們可以滾動,可以考慮使用ListView

現在我們將會討論 LinearLayout 的一些主要屬性,這些屬性在 Flutter 中有所對應。

1.方向(Orientation)

在 LinearLayout 中你可以通過android:orientation=”horizontal”這個屬性來指定子控制元件的排列方向。這個屬性接收horizontal/vertical兩個值,對應 Flutter 中的 Row/Column。

在 Android 中,LinearLayout 是一個ViewGroup,它可以將其他的控制元件作為子控制元件。你可以在 <LinearLayout> </LinearLayout>標籤內宣告它所有的子控制元件。

為了宣告Row/Column的子控制元件,我們需要用到 Row/Columnchildren屬性,這個屬性接收一個控制元件列表(List<Widget>)。如下面程式碼所示:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return  MaterialApp(
      home:  Scaffold(
        appBar:  AppBar(
          title:  Text("LinearLayout Example"),
        ),
        body:  Container(
          color: Colors.yellowAccent,
          child:  Row(
            children: [
               Icon(
                Icons.access_time,
                size: 50.0,
              ),
               Icon(
                Icons.pie_chart,
                size: 100.0,
              ),
               Icon(
                Icons.email,
                size: 50.0,
              )
            ],
          ),
        ),
      ),
    );
  }
}

複製程式碼

在這個例子中,我們使用了Row這個控制元件,相當於設定了android:orientation=”horizontal”的 LinearLayout。如果是垂直的情況我們就用Column

如果你想知道Scaffold在這裡的用處,你可以閱讀我之前的文章在 Flutter 中如何設計 Activity 介面?

下圖是上面程式碼的輸出結果:

[譯]在 Flutter 中如何設計線性佈局?

LinearLayout(屬性) Flutter 部件
android:orientation horizontal Row
android:orientation vertical Column

2."match_parent" 和 "wrap_content"

  • MATCH_PARENT:即控制元件想和父控制元件一樣大,如果你的控制元件是頂級根控制元件,那麼它將和螢幕一樣大。
  • WRAP_CONTENT:即控制元件的大小剛好夠包圍它的內容。

為了獲得與match_parentwrap_content一樣的行為,我們需要用到 Row和 Column 的mainAxisSize屬性,這個屬性接收MainAxisSize列舉。MainAxisSize有兩個值,MainAxisSize.minwrap_content,MainAxisSize.maxmatch_parent

在上面的例子中,我們並沒有給Row指定mainAxisSize屬性,所以它將預設設為MainAxisSize.max,即match_parent。黃色背景展示了容器的剩餘空間是如何被覆蓋的。

下面程式碼演示了在上面例子如何指定mainAxisSize屬性,不同值對應的輸出結果如下圖所示。

....
body: Container(
  color: Colors.yellowAccent,
  child: Row(
    mainAxisSize: MainAxisSize.min,
    children: [...],
  ),
)
...
複製程式碼

[譯]在 Flutter 中如何設計線性佈局?

這樣我們就可以從視覺上區分 mainAxisSize 的不同值是如何應用在 Row 和 Column上的。

3.重力(Gravity)

重力指定了子控制元件如何在自身範圍內定位其內容,我們在LinearLayout中使用android:gravity=”center”屬性指定重力,這個屬性接收多個標識如何對齊的值。在Row和Column中,我們可以使用MainAxisAlignmentCrossAxisAlignment達到同樣的效果。

1.MainAxisAlignment:

這個屬性指定了子控制元件在主軸方向上如何被放置。為了讓這個屬性生效,在Row和Column中必須有剩餘空間。如果你將mainAxisSize屬性設為MainAxisSize.min,那麼設定MainAxisAlignment屬性將會沒有效果,因為沒有剩餘空間可用。

我們可以像下面這樣指定MainAxisAlignment屬性:

....
body: Container(
  color: Colors.yellowAccent,
  child: Row(
    mainAxisSize: MainAxisSize.max,
    mainAxisAlignment: MainAxisAlignment.start,
    children: [...],
  ),
)
...
複製程式碼

一圖勝千言,與其用語言描述每個屬性,不如用圖片來展示更直觀。

下面的輸出比較了 LinearLayout 的屬性和 RowMainAxisAlignment屬性。

[譯]在 Flutter 中如何設計線性佈局?

然後我們來比較一下Column部件:

[譯]在 Flutter 中如何設計線性佈局?

練習:你可以試下其他的列舉:spaceEvenly,spaceAround,spaceBetween,它們與ConstraintLayout中用到了水平/垂直鏈(chain)行為一致。

2.CrossAxisAlignment:

這個屬性指定了子控制元件在交叉軸方向如何放置。即如果我們使用Row部件,那麼子控制元件的重力則基於垂直線;如果我們 使用Column部件,那麼子控制元件的重力則基於水平線。

這聽起來有點讓人費解,不過隨著繼續閱讀你將會理解它。

為了便於理解 ,我們將mainAxisSize設為MainAxisSize.min。你可以像下面程式碼一樣宣告CrossAxisAlignment屬性,如果沒有設定,那麼預設值為CrossAxisAlignment. start

....
body: Container(
  color: Colors.yellowAccent,
  child: Row(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [...],
  ),
)
...
複製程式碼

下圖比較了LinearLayout 的屬性和RowCrossAxisAlignment屬性:

[譯]在 Flutter 中如何設計線性佈局?

下面再來看看Column屬性:

[譯]在 Flutter 中如何設計線性佈局?

stretch表現的有點不一樣,它把控制元件拉伸以佔滿交叉軸剩餘的空間(match_parent)。

4.佈局比重(Layout Weight))

為了建立一個子控制元件平分空間或按一定比例使用空間的線性佈局,我們把每個控制元件的android:layout_height設為0dp(垂直方向)或者把每個控制元件的android:layout_width設為0dp(水平方向),然後把每個控制元件的android:layout_weight設為 1 或者其他你想要分配的值。

在 Flutter 中,為了使用 Row和 Column 達到相同的效果,我們用一個Expanded控制元件來包裹 Row/Column 的子控制元件。Expanded控制元件有一個flex屬性,和android:layout_weight作用是一樣的,因此通過指定flex的值我們就能指定子控制元件所佔的空間比。

下面程式碼演示瞭如何定義控制元件的flex值:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("LinearLayout Example"),
        ),
        body: Container(
          color: Colors.yellowAccent,
          child: Container(
            child: Row(
              children: [
                Expanded(
                  child: Container(
                    child: Icon(
                      Icons.access_time,
                      size: 50.0,
                    ),
                    color: Colors.red,
                  ),
                  flex: 2,
                ),
                Expanded(
                  child: Container(
                    child: Icon(
                      Icons.pie_chart,
                      size: 100.0,
                    ),
                    color: Colors.blue,
                  ),
                  flex: 4,
                ),
                Expanded(
                  child: Container(
                    child: Icon(
                      Icons.email,
                      size: 50.0,
                    ),
                    color: Colors.green,
                  ),
                  flex: 6,
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
複製程式碼

為了便於理解,我們將每個圖示用一個帶背景色的容器控制元件包裹起來,這樣容易看出它們佔用了多少空間:

[譯]在 Flutter 中如何設計線性佈局?

總結

和 Android 中的 LinearLayout 一樣,Row 和 Column 在 Flutter 中也是被重度使用的控制元件,希望在接下來的部落格中討論更多內容。

我建立了一個樣例 App 來演示Row 和 Column 的 屬性以及它們組合起來使用的效果。

[譯]在 Flutter 中如何設計線性佈局?

你可以在這裡看到它。

感謝閱讀。

相關文章