初略講解Flutter的Align(對齊與相對定位)

zane發表於2019-09-11

在上一節我們講過,通過StackPositioned來指定一個或多個子元素相對於父元素各個邊的精確偏移,並且可以重疊。但如果我們只想簡單的調整一個子元素在父元素中的位置的話,使用Align元件會更簡單一些。

Align

Align元件可以調整子元件的位置,並且可以根據子元件的寬高來確定自身的寬高,定義如下:

Align({
  Key key,
  this.alignment = Alignment.center,
  this.widthFactor,
  this.heightFactor,
  Widget child,
})
複製程式碼
  • alignment:需要一個AlignmentGeometry型別的值,表示子元件在父元件中的起始位置。AlignmentGeometry是一個抽象類,它有兩個常用的子類:AlignmentFractionalOffset,我們將在下面的示例中詳細介紹。
  • widthFactorheightFactor是用於確定Align元件本身寬高的屬性;它們是兩個縮放因子,會分別乘以子元素的寬、高,最終的結果就是Align元件的寬高。如果值為null,則Align元件的寬高將會佔用盡可能多的空間。

示例

我們先來看一個簡單的示例:

Container(
  height: 120.0,
  width: 120.0,
  color: Colors.blue[50],
  child: Align(
    alignment: Alignment.topRight,
    child: FlutterLogo(
      size: 60,
    ),
  ),
)
複製程式碼

執行效果如下:

初略講解Flutter的Align(對齊與相對定位)

FlutterLogo是Flutter SDK提供的一個元件,內容就是Flutter的商標。在上面的例子中,我們顯式指定了Container的寬、高都為120。如果我們不顯式指定寬高,而通過同時指定widthFactorheightFactor的值為2,也可以達到同樣的效果,程式碼如下:

Align(
  widthFactor: 2,
  heightFactor: 2,
  alignment: Alignment.topRight,
  child: FlutterLogo(
    size: 60,
  ),
),
複製程式碼

因為FlutterLogo的寬高為60,則Align的最終寬高都為2*60=120

另外,我們通過Alignment.topRightFlutterLogo定位在Container的右上角。那Alignment.topRight是什麼呢?通過查詢SDK原始碼我們可以看到其定義如下:

//右上角
static const Alignment topRight = Alignment(1.0, -1.0);
複製程式碼

可以看到它只是Alignment的一個例項,下面我們介紹一下Alignment

Aligment

Alignment繼承自AlignmentGeometry,表示矩形內的一個點,它有兩個屬性xy,分別表示在水平和垂直方向的偏移,Alignment定義如下:

Alignment(this.x, this.y)
複製程式碼

Alignment元件會以矩形的中心點作為座標原點,即Alignment(0.0, 0.0)x的值從-1到1表示矩形左邊到右邊的距離,y的值從-1到1表示矩形頂部到底部的距離,因此2個水平或垂直單位則等於矩形的寬或高,如Alignment(-1.0, -1.0)代表矩形的左側頂點,而Alignment(1.0, 1.0)代表右側底部終點,而Alignment(1.0, -1.0)則正是右側頂點,即Alignment.topRight。為了使用方便,矩形的原點、四個頂點,以及四條邊的終點在Alignment類中都已經定義為了靜態常量。

Alignment可以通過其座標轉換公式將其座標轉為子元素的具體偏移座標:

(Alignment.x * childWidth/2 + childWidth/2, Alignment.y * childHeight/2 + childHeight/2)
複製程式碼

其中childWidth為子元素的寬度,childHeight為子元素的高度。

現在我們再看看上面的示例,我們將Alignment(1.0, -1.0)帶入上面公式,可得FlutterLogo的實際偏移座標正是(60, 0),下面我們再看一個例子:

Align(
  widthFactor: 2,
  heightFactor: 2,
  alignment: Alignment(2.0, 0.0),
  child: FlutterLogo(
    size: 60,
  ),
)
複製程式碼

現在我們再看看上面的示例,將Alignment(2.0, 0.0)帶入上述座標轉換公式中,可以得到FlutterLogo的實際偏移座標為(90, 30),實際執行效果如下:

初略講解Flutter的Align(對齊與相對定位)

FractionalOffset

FractionalOffset繼承自Alignment,它和Alignment唯一的區別就是座標原點不同!FractionalOffset的座標原點為矩形的左側頂點,這和佈局系統的一致,所以理解起來會比較容易。FractionalOffset的座標轉換公式為:

(FractionalOffset.x * childWidth, FractionalOffset.y * childHeight)
複製程式碼

示例:

Container(
  height: 120.0,
  width: 120.0,
  color: Colors.blue[50],
  child: Align(
    alignment: FractionalOffset(0.2, 0.6),
    child: FlutterLogo(
      size: 60,
    ),
  ),
)
複製程式碼

實際執行效果如下:

初略講解Flutter的Align(對齊與相對定位)

我們將FractionalOffset(0.2, 0.6)帶入座標轉換公式中,可以得到FlutterLogo實際偏移為(12, 36)和實際執行效果吻合。

Align和Stack對比

現在我們都知道,AlignStack/Positioned都可以用於指定子元素相對於父元素的偏移,但它們還是有兩個主要的區別:

  1. 定位參考系統不同;Stack/Positioned定位的參考系可以是父容器矩形的四個頂點;而Align則需要先通過alignment引數來確定座標原點,不同的alignment(如AlignmentFractionalOffset)會對應不同原點,最終的偏移是需要通過alignment的轉換公式來計算出來的。
  2. Stack可以有多個子元素,並且子元素可以堆疊,而Align只能有一個子元素,不存在堆疊。

Align元件與Center元件的關係

我們在前面章節的例子中已經使用過Center元件來居中子元素了,現在我們正式來介紹一下它。通過查詢SDK原始碼,我們看到Center元件定義如下:

class Center extends Align {
  const Center({ 
    Key key, 
    double widthFactor, 
    double heightFactor, 
    Widget child 
  }): super(
    key: key, 
    widthFactor: widthFactor, 
    heightFactor: heightFactor, 
    child: child
  );
}
複製程式碼

可以看到Center繼承自Align,它比Align只少了一個alignment引數;由於Align的建構函式中alignment值為Alignment.center,所以,我們可以認為Center元件其實是對齊方式確定為Alignment.centerAlign

上面我們講過當widthFactorheightFactornullAlign元件的寬高將會佔用盡可能多的空間,這一點需要特別注意,下面我們通過一個示例來說明:

...//省略無關程式碼
DecoratedBox(
  decoration: BoxDecoration(color: Colors.red),
  child: Center(
    child: Text("xxx"),
  ),
),
DecoratedBox(
  decoration: BoxDecoration(color: Colors.red),
  child: Center(
    widthFactor: 1,
    heightFactor: 1,
    child: Text("xxx"),
  ),
)
複製程式碼

執行效果如下:

初略講解Flutter的Align(對齊與相對定位)

總結

本節重點介紹了Align元件及兩種偏移類AlignmentFractionalOffset,讀者需要理解這兩種偏移類的區別及各自的座標轉化公式。另外,建議讀者在需要制定一些精確的偏移時應優先使用FractionalOffset,因為它的座標原點和佈局系統相同,能更容易算出實際偏移。

緊接著,我們又介紹了Align元件和Stack/Positioned元件的對比,以及與Center的關係,讀者可以對比理解。

最後,熟悉Web開發的同學可能會發現Align元件的特性和Web開發中相對定位(position: relative)非常相似。是的!在大多數時候,我們可以直接使用Align元件來實現Web中相對定位的效果,讀者可以類比記憶。

相關文章