Flutter實戰(zhàn) 對齊與相對定位(Align)

2021-03-08 10:07 更新

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

#4.6.1 Align

Align 組件可以調(diào)整子組件的位置,并且可以根據(jù)子組件的寬高來確定自身的的寬高,定義如下:

Align({
  Key key,
  this.alignment = Alignment.center,
  this.widthFactor,
  this.heightFactor,
  Widget child,
})

  • alignment : 需要一個AlignmentGeometry類型的值,表示子組件在父組件中的起始位置。AlignmentGeometry 是一個抽象類,它有兩個常用的子類:AlignmentFractionalOffset,我們將在下面的示例中詳細介紹。
  • widthFactorheightFactor是用于確定Align 組件本身寬高的屬性;它們是兩個縮放因子,會分別乘以子元素的寬、高,最終的結(jié)果就是Align 組件的寬高。如果值為null,則組件的寬高將會占用盡可能多的空間。

#示例

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

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

運行效果如圖4-11所示:

FlutterLogo 是 Flutter SDK 提供的一個組件,內(nèi)容就是 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是什么呢?通過源碼我們可以看到其定義如下:

//右上角
static const Alignment topRight = Alignment(1.0, -1.0);

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

#Alignment

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

Alignment(this.x, this.y)

Alignment Widget 會以矩形的中心點作為坐標原點,即Alignment(0.0, 0.0) 。xy的值從-1到1分別代表矩形左邊到右邊的距離和頂部到底邊的距離,因此2個水平(或垂直)單位則等于矩形的寬(或高),如Alignment(-1.0, -1.0) 代表矩形的左側(cè)頂點,而Alignment(1.0, 1.0)代表右側(cè)底部終點,而Alignment(1.0, -1.0) 則正是右側(cè)頂點,即Alignment.topRight。為了使用方便,矩形的原點、四個頂點,以及四條邊的終點在Alignment類中都已經(jīng)定義為了靜態(tài)常量。

Alignment可以通過其坐標轉(zhuǎn)換公式將其坐標轉(zhuǎn)為子元素的具體偏移坐標:

(Alignment.x*childWidth/2+childWidth/2, Alignment.y*childHeight/2+childHeight/2)

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

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

 Align(
  widthFactor: 2,
  heightFactor: 2,
  alignment: Alignment(2,0.0),
  child: FlutterLogo(
    size: 60,
  ),
)

我們可以先想象一下運行效果:將Alignment(2,0.0)帶入上述坐標轉(zhuǎn)換公式,可以得到FlutterLogo的實際偏移坐標為(90,30)。實際運行如圖4-12所示:

#FractionalOffset

FractionalOffset 繼承自 Alignment,它和 Alignment唯一的區(qū)別就是坐標原點不同!FractionalOffset 的坐標原點為矩形的左側(cè)頂點,這和布局系統(tǒng)的一致,所以理解起來會比較容易。FractionalOffset的坐標轉(zhuǎn)換公式為:

實際偏移 = (FractionalOffse.x * childWidth, FractionalOffse.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,
    ),
  ),
)

實際運行效果如圖4-13所示下:

我們將FractionalOffset(0.2, 0.6)帶入坐標轉(zhuǎn)換公式得FlutterLogo實際偏移為(12,36),和實際運行效果吻合。

#4.6.2 Align和Stack對比

可以看到,AlignStack/Positioned都可以用于指定子元素相對于父元素的偏移,但它們還是有兩個主要區(qū)別:

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

#4.6.3 Center組件

我們在前面章節(jié)的例子中已經(jīng)使用過Center組件來居中子元素了,現(xiàn)在我們正式來介紹一下它。通過查找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 參數(shù);由于Align的構(gòu)造函數(shù)中alignment 值為Alignment.center,所以,我們可以認為Center組件其實是對齊方式確定(Alignment.center)了的Align。

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

...//省略無關(guān)代碼
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"),
  ),
)

運行效果如圖4-14所示:

#總結(jié)

本節(jié)重點介紹了Align組件及兩種偏移類AlignmentFractionalOffset,讀者需要理解這兩種偏移類的區(qū)別及各自的坐標轉(zhuǎn)化公式。另外,在此建議讀者在需要制定一些精確的偏移時應(yīng)優(yōu)先使用FractionalOffset,因為它的坐標原點和布局系統(tǒng)相同,能更容易算出實際偏移。

在后面,我們又介紹了Align組件和Stack/PositionedCenter的關(guān)系,讀者可以對比理解。

還有,熟悉 Web 開發(fā)的同學(xué)可能會發(fā)現(xiàn)Align組件的特性和 Web 開發(fā)中相對定位(position: relative)非常像,是的!在大多數(shù)時候,我們可以直接使用Align組件來實現(xiàn) Web 中相對定位的效果,讀者可以類比記憶。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號