Flutter 佈局(二)- Padding、Align、Center詳解

来源:https://www.cnblogs.com/holy-loki/archive/2018/10/06/9735045.html
-Advertisement-
Play Games

本文主要介紹Flutter佈局中的Padding、Align以及Center控制項,詳細介紹了其佈局行為以及使用場景,並對源碼進行了分析。 ...


本文主要介紹Flutter佈局中的Padding、Align以及Center控制項,詳細介紹了其佈局行為以及使用場景,並對源碼進行了分析。

1. Padding

A widget that insets its child by the given padding.

1.1 簡介

Padding在Flutter中用的也挺多的,作為一個基礎的控制項,功能非常單一,給子節點設置padding屬性。寫過其他端的都瞭解這個屬性,就是設置內邊距屬性,內邊距的空白區域,也是widget的一部分。

Flutter中並沒有單獨的Margin控制項,在Container中有margin屬性,看源碼關於margin的實現。

if (margin != null)
  current = new Padding(padding: margin, child: current);

不難看出,Flutter中淡化了margin以及padding的區別,margin實質上也是由Padding實現的。

1.2 佈局行為

Padding的佈局分為兩種情況:

  • 當child為空的時候,會產生一個寬為left+right,高為top+bottom的區域;
  • 當child不為空的時候,Padding會將佈局約束傳遞給child,根據設置的padding屬性,縮小child的佈局尺寸。然後Padding將自己調整到child設置了padding屬性的尺寸,在child周圍創建空白區域。

1.3 繼承關係

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > Padding

從繼承關係可以看出,Padding控制項是一個基礎控制項,不像Container這種組合控制項。Container中的margin以及padding屬性都是利用Padding控制項去實現的。

1.3.1 關於SingleChildRenderObjectWidget

SingleChildRenderObjectWidget是RenderObjectWidgets的一個子類,用於限制只能有一個子節點。它只提供child的存儲,而不提供實際的更新邏輯。

1.3.2 關於RenderObjectWidgets

RenderObjectWidgets為RenderObjectElement提供配置,而RenderObjectElement包含著(wrap)RenderObject,RenderObject則是在應用中提供實際的繪製(rendering)的元素。

1.4 示例代碼

實例代碼直接上官方的例子,非常的簡單:

new Padding(
  padding: new EdgeInsets.all(8.0),
  child: const Card(child: const Text('Hello World!')),
)

例子中對Card設置了一個寬度為8的內邊距。

1.5 源碼解析

構造函數如下:

const Padding({
    Key key,
    @required this.padding,
    Widget child,
  })

包含一個padding屬性,相當的簡單。

1.5.1 屬性解析

padding:padding的類型為EdgeInsetsGeometry,EdgeInsetsGeometry是EdgeInsets以及EdgeInsetsDirectional的基類。在實際使用中不涉及到國際化,例如適配阿拉伯地區等,一般都是使用EdgeInsets。EdgeInsetsDirectional光看命名就知道跟方向相關,因此它的四個邊距不限定上下左右,而是根據方向來定的。

1.5.2 源碼

@override
  RenderPadding createRenderObject(BuildContext context) {
    return new RenderPadding(
      padding: padding,
      textDirection: Directionality.of(context),
   );
}

Padding的創建函數,實際上是由RenderPadding來進行的。

關於RenderPadding的實際佈局表現,當child為null的時候:

if (child == null) {
  size = constraints.constrain(new Size(
    _resolvedPadding.left + _resolvedPadding.right,
    _resolvedPadding.top + _resolvedPadding.bottom
  ));
  return;
}

返回一個寬為_resolvedPadding.left+_resolvedPadding.right,高為_resolvedPadding.top+_resolvedPadding.bottom的區域。

當child不為null的時候,經歷了三個過程,即調整child尺寸、調整child位置以及調整Padding尺寸,最終達到實際的佈局效果。

// 調整child尺寸
final BoxConstraints innerConstraints = constraints.deflate(_resolvedPadding);
child.layout(innerConstraints, parentUsesSize: true);

// 調整child位置
final BoxParentData childParentData = child.parentData;
childParentData.offset = new Offset(_resolvedPadding.left, _resolvedPadding.top);

// 調整Padding尺寸
size = constraints.constrain(new Size(
  _resolvedPadding.left + child.size.width + _resolvedPadding.right,
  _resolvedPadding.top + child.size.height + _resolvedPadding.bottom
));

到此處,上面介紹的padding佈局行為就解釋的通了。

1.6 使用場景

Padding本身還是挺簡單的,基本上需要間距的地方,它都能夠使用。如果在單一的間距場景,使用Padding比Container的成本要小一些,畢竟Container裡面包含了多個widget。Padding能夠實現的,Container都能夠實現,只不過,Container更加的複雜。

2. Align

A widget that aligns its child within itself and optionally sizes itself based on the child's size.

2.1 簡介

在其他端的開發,Align一般都是當做一個控制項的屬性,並沒有拿出來當做一個單獨的控制項。Align本身實現的功能並不複雜,設置child的對齊方式,例如居中、居左居右等,並根據child尺寸調節自身尺寸。

2.2 佈局行為

Align的佈局行為分為兩種情況:

  • 當widthFactor和heightFactor為null的時候,當其有限制條件的時候,Align會根據限制條件儘量的擴展自己的尺寸,當沒有限制條件的時候,會調整到child的尺寸;
  • 當widthFactor或者heightFactor不為null的時候,Aligin會根據factor屬性,擴展自己的尺寸,例如設置widthFactor為2.0的時候,那麼,Align的寬度將會是child的兩倍。

Align為什麼會有這樣的佈局行為呢?原因很簡單,設置對齊方式的話,如果外層元素尺寸不確定的話,內部的對齊就無法確定。因此,會有寬高因數、根據外層限制擴大到最大尺寸、外層不確定時調整到child尺寸這些行為。

2.3 繼承關係

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > Align

可以看出,Align跟Padding一樣,也是一個非常基礎的組件,Container中的align屬性,也是使用Align去實現的。

2.4 示例代碼

new Align(
  alignment: Alignment.center,
  widthFactor: 2.0,
  heightFactor: 2.0,
  child: new Text("Align"),
)

例子依舊很簡單,設置一個寬高為child兩倍區域的Align,其child處在正中間。

2.5 源碼解析

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

Align的構造函數基本上就是寬高因數、對齊方式屬性。日常使用中,寬高因數屬性基本上用的不多。如果是複雜的佈局,Container內部的align屬性也可以實現相同的效果。

2.5.1 屬性解析

alignment:對齊方式,一般會使用系統預設提供的9種方式,但是並不是說只有這9種,例如如下的定義。系統提供的9種方式只是預先定義好的。

/// The top left corner.
static const Alignment topLeft = const Alignment(-1.0, -1.0);

Alignment實際上是包含了兩個屬性的,其中第一個參數,-1.0是左邊對齊,1.0是右邊對齊,第二個參數,-1.0是頂部對齊,1.0是底部對齊。根據這個規則,我們也可以自定義我們需要的對齊方式,例如

/// 居右高於底部1/4處.
static const Alignment rightHalfBottom = alignment: const Alignment(1.0, 0.5),

widthFactor:寬度因數,如果設置的話,Align的寬度就是child的寬度乘以這個值,不能為負數。

heightFactor:高度因數,如果設置的話,Align的高度就是child的高度乘以這個值,不能為負數。

2.5.2 源碼

@override
  RenderPositionedBox createRenderObject(BuildContext context) {
    return new RenderPositionedBox(
      alignment: alignment,
      widthFactor: widthFactor,
      heightFactor: heightFactor,
      textDirection: Directionality.of(context),
    );
  }

Align的實際構造調用的是RenderPositionedBox

RenderPositionedBox的佈局表現如下:

// 根據_widthFactor、_heightFactor以及限制因素來確定寬高
final bool shrinkWrapWidth = _widthFactor != null || constraints.maxWidth == double.infinity;
final bool shrinkWrapHeight = _heightFactor != null || constraints.maxHeight == double.infinity;

if (child != null) {
  //  如果child不為null,則根據規則設置Align的寬高,如果需要縮放,則根據_widthFactor是否為null來進行縮放,如果不需要,則儘量擴展。
  child.layout(constraints.loosen(), parentUsesSize: true);
  size = constraints.constrain(new Size(shrinkWrapWidth ? child.size.width * (_widthFactor ?? 1.0) : double.infinity,
                                        shrinkWrapHeight ? child.size.height * (_heightFactor ?? 1.0) : double.infinity));
  alignChild();
} else {
  // 如果child為null,如果需要縮放,則變為0,否則就儘量擴展
  size = constraints.constrain(new Size(shrinkWrapWidth ? 0.0 : double.infinity,
                                        shrinkWrapHeight ? 0.0 : double.infinity));
}

2.6 使用場景

一般在對齊場景下使用,例如需要右對齊或者底部對齊之類的。它能夠實現的功能,Container都能實現。

3. Center

Center繼承自Align,只不過是將alignment設置為Alignment.center,其他屬性例如widthFactor、heightFactor,佈局行為,都與Align完全一樣,在這裡就不再單獨做介紹了。Center源碼如下,沒有設置alignment屬性,是因為Align預設的對齊方式就是居中。

class Center extends Align {
  /// Creates a widget that centers its child.
  const Center({ Key key, double widthFactor, double heightFactor, Widget child })
    : super(key: key, widthFactor: widthFactor, heightFactor: heightFactor, child: child);
}

4. 後話

筆者建了一個flutter學習相關的項目,github地址,裡面包含了筆者寫的關於flutter學習相關的一些文章,會定期更新,也會上傳一些學習demo,歡迎大家關註。

5. 參考

  1. Padding class
  2. EdgeInsetsGeometry class
  3. EdgeInsets class
  4. EdgeInsetsDirectional class
  5. RenderPadding class
  6. Align class
  7. Center class

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 測試環境: create table bqh6 (xm varchar2(10),bmbh number(2),bmmc varchar2(15),gz int);insert into bqh6 values ('張三',01,'技術支持',3500);insert into bqh6 value ...
  • 步驟一:安裝mysql依賴 步驟二:下載mysql社區版 步驟三:創建mysql用戶和用戶組 步驟四:解壓mysql文件 步驟五:創建文件夾 步驟六:初始化mysql 將root初始化密碼複製出來,等會登錄mysql需要使用這個密碼 步驟七:分配mysql文件夾許可權 步驟八:啟動mysql 步驟九: ...
  • 本文將在MySQL源碼探索系列技術博客的第1篇的基礎上接著分析dispatch_command()函數之後的工作流程,主要是分析mysql_parse()和mysql_execute_command()兩個函數的代碼框架,並對其中涉及到的隱式事務如何判斷等等問題結合MySQL源碼進行了介紹。 本人技 ...
  • Oracle用戶 Oracle用戶創建和授權詳解,參考網址如下: http://www.oraclejsq.com/getOracle_jcjc.do?nodeid=010100133 oracle用戶的概念對於Oracle資料庫至關重要,在現實環境當中一個伺服器一般只會安裝一個Oracle實例,一 ...
  • 點進來的同學,大部分是為了學編程而來的,這裡面有一部分學編程是出於興趣愛好,但大部分都是為了找工作或跳槽吧!其中有些人也許是覺得難,也許是遇到瓶頸,也許是因為惰性,總之半途而廢了。在這新一年的開始,我想對你說一句:不要輕易放棄,如果你覺得艱難,說明你正在走上坡路!在為你講為什麼要學習大數據前給分享一 ...
  • 據外媒phonearena報道,估計有3200萬台Android設備很快就無法使用谷歌Chrome移動瀏覽器。根據XDA最近提交的一份文件顯示,Chrome移動瀏覽器應用程式的最低API級別將從4.1提高到4.4。 這意味著仍然運行由Jelly Bean(Jelly Bean是Android 4.1 ...
  • 一、概述 在 RxJava 中,一個實現了 介面的對象可以訂閱一個 類的實例。訂閱者對 發射的任何數據或數據序列作出響應。這種模式簡化了併發操作,因為它不需要阻塞等待 發射數據,而是創建了一個處於待命狀態的觀察者哨兵,哨兵在未來某個時刻響應 的通知。RxJava 提供了一套非同步編程的 API,並且支 ...
  • 列表視圖 為實現各種排列組合類的視圖(包括但不限於Spinner、ListView、GridView等等),Android提供了五花八門的適配器用於組裝某個規格的數據,常見的適配器有:數組適配器ArrayAdapter、簡單適配器SimpleAdapter、基本適配器BaseAdapter、翻頁適配 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...