Flutter 佈局(三)- FittedBox、AspectRatio、ConstrainedBox詳解

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

本文主要介紹Flutter佈局中的FittedBox、AspectRatio、ConstrainedBox,詳細介紹了其佈局行為以及使用場景,並對源碼進行了分析。 ...


本文主要介紹Flutter佈局中的FittedBox、AspectRatio、ConstrainedBox,詳細介紹了其佈局行為以及使用場景,並對源碼進行了分析。

1. FittedBox

Scales and positions its child within itself according to fit.

1.1 簡介

按照其官方的介紹,它主要做了兩件事情,縮放(Scale)以及位置調整(Position)。

FittedBox會在自己的尺寸範圍內縮放並且調整child位置,使得child適合其尺寸。做過移動端的,可能會聯想到ImageView控制項,它是將圖片在其範圍內,按照規則,進行縮放位置調整。FittedBox跟ImageView是有些類似的,可以猜測出,它肯定有一個類似於ScaleType的屬性。

1.2 佈局行為

FittedBox的佈局行為還算簡單,官方沒有給出說明,我在這裡簡單說一下。由於FittedBox是一個容器,需要讓其child在其範圍內縮放,因此其佈局行為分兩種情況:

  • 如果外部有約束的話,按照外部約束調整自身尺寸,然後縮放調整child,按照指定的條件進行佈局;
  • 如果沒有外部約束條件,則跟child尺寸一致,指定的縮放以及位置屬性將不起作用。

1.3 繼承關係

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > FittedBox

從繼承關係可以看出,FittedBox控制項是一個基礎控制項。

1.4 示例代碼

new Container(
  color: Colors.amberAccent,
  width: 300.0,
  height: 300.0,
  child: new FittedBox(
    fit: BoxFit.contain,
    alignment: Alignment.topLeft,
    child: new Container(
      color: Colors.red,
      child: new Text("FittedBox"),
    ),
  ),
)

寫了一個很簡單的例子,加入Container是為了加顏色顯示兩個區域,讀者可以試著修改fit以及alignment查看其不同的效果。

1.5 源碼解析

const FittedBox({
Key key,
this.fit: BoxFit.contain,
this.alignment: Alignment.center,
Widget child,
})

1.5.1 屬性解析

fit:縮放的方式,預設的屬性是BoxFit.contain,child在FittedBox範圍內,儘可能的大,但是不超出其尺寸。這裡註意一點,contain是保持著child寬高比的大前提下,儘可能的填滿,一般情況下,寬度或者高度達到最大值時,就會停止縮放。

BoxFit佈局表現

alignment:對齊方式,預設的屬性是Alignment.center,居中顯示child。

1.5.2 源碼

構造函數如下:

@override
RenderFittedBox createRenderObject(BuildContext context) {
return new RenderFittedBox(
  fit: fit,
  alignment: alignment,
  textDirection: Directionality.of(context),
);
}

FittedBox具體實現是由RenderFittedBox進行的。不知道讀者有沒有發現,目前的一些基礎控制項,繼承自RenderObjectWidget的,widget本身都只是存儲了一些配置信息,真正的繪製渲染,則是由內部的createRenderObject所調用的RenderObject去實現的。

RenderFittedBox具體的佈局代碼如下:

if (child != null) {
  child.layout(const BoxConstraints(), parentUsesSize: true);
  // 如果child不為null,則按照child的尺寸比率縮放child的尺寸
  size = constraints.constrainSizeAndAttemptToPreserveAspectRatio(child.size);
  _clearPaintData();
} else {
  // 如果child為null,則按照最小尺寸進行佈局
  size = constraints.smallest;
}

1.6 使用場景

FittedBox在目前的項目中還未用到過。對於需要縮放調整位置處理的,一般都是圖片。筆者一般都是使用Container中的decoration屬性去實現相應的效果。對於其他控制項需要縮放以及調整位置的,目前還沒有遇到使用場景,大家只需要知道有這麼一個控制項,可以實現這個功能即可。

2. AspectRatio

A widget that attempts to size the child to a specific aspect ratio.

2.1 簡介

AspectRatio的作用是調整child到設置的寬高比,這種控制項在其他移動端平臺上一般都不會提供,Flutter之所以提供,我想最大的原因,可能就是自定義起來特別麻煩吧。

2.2 佈局行為

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

  • AspectRatio首先會在佈局限制條件允許的範圍內儘可能的擴展,widget的高度是由寬度和比率決定的,類似於BoxFit中的contain,按照固定比率去儘量占滿區域。
  • 如果在滿足所有限制條件過後無法找到一個可行的尺寸,AspectRatio最終將會去優先適應佈局限制條件,而忽略所設置的比率。

2.3 繼承關係

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > AspectRatio

從繼承關係看,AspectRatio是基礎的佈局控制項。

2.4 示例代碼

new Container(
  height: 200.0,
  child: new AspectRatio(
    aspectRatio: 1.5,
    child: new Container(
      color: Colors.red,
    ),
  ),
);

示例代碼是定義了一個高度為200的區域,內部AspectRatio比率設置為1.5,最終AspectRatio的是寬300高200的一個區域。

2.5 源碼解析

構造函數如下:

const AspectRatio({
Key key,
@required this.aspectRatio,
Widget child
}) 

構造函數只包含了一個aspectRatio屬性,其中aspectRatio不能為null。

2.5.1 屬性解析

aspectRatio:aspectRatio是寬高比,最終可能不會根據這個值去佈局,具體則要看綜合因素,外層是否允許按照這種比率進行佈局,只是一個參考值。

2.5.2 源碼

@override
  RenderAspectRatio createRenderObject(BuildContext context) => new RenderAspectRatio(aspectRatio: aspectRatio);

經過前面一些控制項的解析,我想大家對這種構造應該不會再陌生了,繪製都是交由RenderObject去完成的,這裡則是由RenderAspectRatio去完成具體的繪製工作。

RenderAspectRatio的構造函數中會對aspectRatio做一些檢測(assert)

  • aspectRatio不能為null;
  • aspectRatio必須大於0;
  • aspectRatio必須是有限的。

接下來我們來看一下RenderAspectRatio的具體尺寸計算函數:

  • 如果限制條件為isTight,則返回最小的尺寸(constraints.smallest);
if (constraints.isTight)
  return constraints.smallest;
  • 如果寬度為有限的值,則將高度設置為width / _aspectRatio。 如果寬度為無限,則將高度設為最大高度,寬度設為height * _aspectRatio;
if (width.isFinite) {
  height = width / _aspectRatio;
} else {
  height = constraints.maxHeight;
  width = height * _aspectRatio;
}
  • 接下來則是在限制範圍內調整寬高,總體思想則是寬度優先,大於最大值則設為最大值,小於最小值,則設為最小值。

如果寬度大於最大寬度,則將其設為最大寬度,高度設為width / _aspectRatio;

if (width > constraints.maxWidth) {
  width = constraints.maxWidth;
  height = width / _aspectRatio;
}

如果高度大於最大高度,則將其設為最大高度,寬度設為height * _aspectRatio;

if (height > constraints.maxHeight) {
  height = constraints.maxHeight;
  width = height * _aspectRatio;
}

如果寬度小於最小寬度,則將其設為最小寬度,高度設為width / _aspectRatio;

if (width < constraints.minWidth) {
  width = constraints.minWidth;
  height = width / _aspectRatio;
}

如果高度小於最小高度,則將其設為最小高度,寬度設為height * _aspectRatio。

if (height < constraints.minHeight) {
  height = constraints.minHeight;
  width = height * _aspectRatio;
}

2.6 使用場景

AspectRatio適用於需要固定寬高比的情景下。筆者最近使用這個控制項的場景是相機,相機的預覽尺寸都是固定的幾個值,因此不能隨意去設置相機的顯示區域,必須按照比率進行顯示,否則會出現拉伸的情況。除此之外,倒是用的不多。

3. ConstrainedBox

A widget that imposes additional constraints on its child.

3.1 簡介

這個控制項的作用是添加額外的限制條件(constraints)到child上,本身挺簡單的,可以被一些控制項替換使用。Flutter的佈局控制項體系,梳理著發現確實有點亂,感覺總體思想是缺啥就造啥,哈哈。

3.2 佈局行為

ConstrainedBox的佈局行為非常簡單,取決於設置的限制條件,而關於父子節點的限制因素生效優先順序,可以查看之前的文章,在這裡就不做具體敘述了。

3.3 繼承關係

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > ConstrainedBox

ConstrainedBox也是一個基礎的佈局控制項。

3.4 示例代碼

new ConstrainedBox(
  constraints: const BoxConstraints(
    minWidth: 100.0,
    minHeight: 100.0,
    maxWidth: 150.0,
    maxHeight: 150.0,
  ),
  child: new Container(
    width: 200.0,
    height: 200.0,
    color: Colors.red,
  ),
);

例子也挺簡單的,在一個寬高200.0的Container上添加一個約束最大最小寬高的ConstrainedBox,實際的顯示中,則是一個寬高為150.0的區域。

3.5 源碼解析

構造函數如下:

ConstrainedBox({
Key key,
@required this.constraints,
Widget child
})

包含了一個constraints屬性,且不能為null。

3.5.1 屬性解析

constraints:添加到child上的額外限制條件,其類型為BoxConstraints。BoxConstraints的作用是幹啥的呢?其實很簡單,就是限制各種最大最小寬高。說到這裡插一句,double.infinity在widget佈局的時候是合法的,也就說,例如想最大的擴展寬度,可以將寬度值設為double.infinity。

3.5.2 源碼

@override
RenderConstrainedBox createRenderObject(BuildContext context) {
return new RenderConstrainedBox(additionalConstraints: constraints);
}

RenderConstrainedBox實現其繪製。其具體的佈局表現分兩種情況:

  • 如果child不為null,則將限制條件加在child上;
  • 如果child為null,則會儘可能的縮小尺寸。

具體代碼如下:

@override
void performLayout() {
if (child != null) {
  child.layout(_additionalConstraints.enforce(constraints), parentUsesSize: true);
  size = child.size;
} else {
  size = _additionalConstraints.enforce(constraints).constrain(Size.zero);
}
}

3.6 使用場景

需要添加額外的約束條件可以使用此控制項,例如設置最小寬高,儘可能的占用區域等等。筆者在實際開發中使用的倒不是很多,倒不是說這個控制項不好使用,而是好多約束因素是綜合的,例如需要額外的設置margin、padding屬性能,因此單獨再套個這個就顯得很繁瑣了。

3.7 關於UnconstrainedBox

這個控制項不做詳細介紹了,它跟ConstrainedBox相反,是不添加任何約束條件到child上,讓child按照其原始的尺寸渲染。

很神奇是吧,我也覺得,其實它的作用就是給child一個儘可能大的空間,不加約束的讓其顯示。用處我暫時木有想到。只能說Flutter生產Widget很隨性。

4. 後話

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

5. 參考

  1. FittedBox class
  2. BoxFit enum
  3. AspectRatio class
  4. ConstrainedBox class
  5. BoxConstraints class
  6. UnconstrainedBox class

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

-Advertisement-
Play Games
更多相關文章
  • MySQL集群架構系列將討論MySQL集群架構的幾種最常見形式解決的問題,實現原理,存在的問題,以及環境搭建步驟。 本文主要討論MySQL架構關註的問題。 1.高可用的作用 在MySQL的高可用架構中,高可用的作用簡單來講就是保證整個架構的對外服務不會出現中斷,即通過技術手段避免單點故障引起架構整體 ...
  • MySQL的字元串是從1開始編號的,這與電腦編程語言有所不同,在MySQL中1代表第一個字元,-1代表最後一個字元,以此類推。 MySQL中百分號“%”代表的是任意個字元,下劃線“_”代表的是任意一個字元。 ...
  • 本文配置主從使用的操作系統是Centos7,資料庫版本是mysql5.7。 準備好兩台安裝有mysql的機器(mysql安裝教程鏈接) 主資料庫配置 每個從資料庫會使用一個MySQL賬號來連接主資料庫,所以我們要在主資料庫里創建一個賬號,並且該賬號要授予 REPLICATION SLAVE 許可權 創 ...
  • #創建資料庫create database ST CHARACTER set utf8;#創建用戶create user ST identified by '19980510';#授權用戶操作該資料庫grant all on ST.* to ST; #創建學生表create table Studen ...
  • 1.環境準備 RHEL7.4(最小化安裝) 64bit 2G 記憶體 (1G 記憶體編譯將近一個小時) 磁碟空間 15G 以上。 配置為本地yum 源 從MySQL5.7版本開始,安裝MySQL需要依賴 Boost 的C++擴展,而且只能是 1.59.0 版本; 2.cmake簡介 從mysql5.5起 ...
  • 大數據又稱黑暗數據,是指人腦無法處理的海量數據聚合成的信息資產,在民生、IT、金融、農業、通信等方面都有廣泛應用。未來5年大數據行業呈井噴趨勢,人才需求火爆,2018年大數據人才缺口更是高達900萬。以後想要做大數據相關的工作,需要學習哪些技術知識? 羅馬不是一天建成的,大數據工程師也不是短時間能鍛 ...
  • RDB RDB是將當前數據生成快照保存到硬碟上。 RDB的工作流程: 1. 執行bgsave命令,Redis父進程判斷當前是否存在正在執行的子進程,如RDB/AOF子進程,如果存在bgsave命令直接返回。 2. 父進程執行fork操作創建子進程,fork操作過程中父進程被阻塞。 3. 父進程for ...
  • 本文對Flutter的29種佈局控制項進行了總結分類,講解一些佈局上的優化策略,以及面對具體的佈局時,如何去選擇控制項。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...