Flutter 佈局(四)- Baseline、FractionallySizedBox、IntrinsicHeight、IntrinsicWidth詳解

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

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


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

1. Baseline

A widget that positions its child according to the child's baseline.

1.1 簡介

Baseline這個控制項,做過移動端開發的都會瞭解過,一般文字排版的時候,可能會用到它。它的作用很簡單,根據child的baseline,來調整child的位置。例如兩個字型大小不一樣的文字,希望底部在一條水平線上,就可以使用這個控制項,是一個非常基礎的控制項。

關於字元的Baseline,可以看下下麵這張圖,這具體就涉及到了字體排版,感興趣的同學可以自行瞭解。

Baseline

1.2 佈局行為

Baseline控制項佈局行為分為兩種情況:

  • 如果child有baseline,則根據child的baseline屬性,調整child的位置;
  • 如果child沒有baseline,則根據child的bottom,來調整child的位置。

1.3 繼承關係

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > Baseline

1.4 示例代碼

new Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: <Widget>[
    new Baseline(
      baseline: 50.0,
      baselineType: TextBaseline.alphabetic,
      child: new Text(
        'TjTjTj',
        style: new TextStyle(
          fontSize: 20.0,
          textBaseline: TextBaseline.alphabetic,
        ),
      ),
    ),
    new Baseline(
      baseline: 50.0,
      baselineType: TextBaseline.alphabetic,
      child: new Container(
        width: 30.0,
        height: 30.0,
        color: Colors.red,
      ),
    ),
    new Baseline(
      baseline: 50.0,
      baselineType: TextBaseline.alphabetic,
      child: new Text(
        'RyRyRy',
        style: new TextStyle(
          fontSize: 35.0,
          textBaseline: TextBaseline.alphabetic,
        ),
      ),
    ),
  ],
)

上述運行結果是左右兩個文本跟中間的Container底部在一個水平線上,這也印證了Baseline的佈局行為。

Baseline樣例

1.5 源碼解析

const Baseline({
  Key key,
  @required this.baseline,
  @required this.baselineType,
  Widget child
})

1.5.1 屬性解析

baseline:baseline數值,必須要有,從頂部算。

baselineType:bseline類型,也是必須要有的,目前有兩種類型:

  • alphabetic:對齊字元底部的水平線;
  • ideographic:對齊表意字元的水平線。

1.5.2 源碼

我們來看看源碼中具體計算尺寸的這段代碼

child.layout(constraints.loosen(), parentUsesSize: true);
final double childBaseline = child.getDistanceToBaseline(baselineType);
final double actualBaseline = baseline;
final double top = actualBaseline - childBaseline;
final BoxParentData childParentData = child.parentData;
childParentData.offset = new Offset(0.0, top);
final Size childSize = child.size;
size = constraints.constrain(new Size(childSize.width, top + childSize.height));

getDistanceToBaseline這個函數是獲取baseline數值的,存在的話,就取這個值,不存在的話,則取其高度。

整體的計算過程:

  1. 獲取child的 baseline 值;
  2. 計算出top值,其為 baseline - childBaseline,這個值有可能為負數;
  3. 計算出Baseline控制項尺寸,寬度為child的,高度則為 top + childSize.height。

1.6 使用場景

跟字元對齊相關的會用到,其他場景暫時沒有想到。

2. FractionallySizedBox

A widget that sizes its child to a fraction of the total available space

2.1 簡介

FractionallySizedBox控制項會根據現有空間,來調整child的尺寸,所以說child就算設置了具體的尺寸數值,也不起作用。

2.2 佈局行為

FractionallySizedBox的佈局行為主要跟它的寬高因數兩個參數有關,當參數為null或者有具體數值的時候,佈局表現不一樣。當然,還有一個輔助參數alignment,作為對齊方式進行佈局。

  • 當設置了具體的寬高因數,具體的寬高則根據現有空間寬高 * 因數,有可能會超出父控制項的範圍,當寬高因數大於1的時候;
  • 當沒有設置寬高因數,則填滿可用區域;

2.3 繼承關係

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > FractionallySizedBox

2.4 示例代碼

new Container(
    color: Colors.blue,
    height: 150.0,
    width: 150.0,
    padding: const EdgeInsets.all(10.0),
    child: new FractionallySizedBox(
      alignment: Alignment.topLeft,
      widthFactor: 1.5,
      heightFactor: 0.5,
      child: new Container(
        color: Colors.red,
      ),
    ),
  )

運行效果如下所示

FractionallySizedBox例子

2.5 源碼解析

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

2.5.1 屬性解析

alignment:對齊方式,不能為null。

widthFactor:寬度因數,跟之前介紹的控制項類似,寬度乘以這個值,就是最後的寬度。

heightFactor:高度因數,用作計算最後實際高度的。

其中widthFactor和heightFactor都有一個規則

  • 如果不為null,那麼實際的最大寬高度則為child的寬高乘以這個因數;
  • 如果為null,那麼child的寬高則會儘量充滿整個區域。

2.5.2 源碼

FractionallySizedBox內部具體渲染是由RenderFractionallySizedOverflowBox來實現的,通過命名就可以看出,這個控制項可能會Overflow。

我們直接看實際計算尺寸的代碼

double minWidth = constraints.minWidth;
double maxWidth = constraints.maxWidth;
if (_widthFactor != null) {
  final double width = maxWidth * _widthFactor;
  minWidth = width;
  maxWidth = width;
}
double minHeight = constraints.minHeight;
double maxHeight = constraints.maxHeight;
if (_heightFactor != null) {
  final double height = maxHeight * _heightFactor;
  minHeight = height;
  maxHeight = height;
}

源代碼中,根據寬高因數是否存在,來進行相對應的尺寸計算。這個過程非常簡單,不再贅述。

2.6 使用場景

當需要在一個區域裡面取百分比尺寸的時候,可以使用這個,比方說,高度40%寬度70%的區域。當然,AspectRatio也可以達到近似的效果。

3. IntrinsicHeight

A widget that sizes its child to the child's intrinsic height.

3.1 簡介

IntrinsicHeight的作用是調整child到固定的高度。這個控制項筆者也是看了很久,不知道它的作用是什麼,官方說這個很有用,但是應該儘量少用,因為其效率問題。

3.2 佈局行為

這個控制項的作用,是將可能高度不受限制的child,調整到一個合適並且合理的尺寸。

3.3 繼承關係

Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > IntrinsicHeight

3.4 示例代碼

new IntrinsicHeight(
  child: new Row(
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
    children: <Widget>[
      new Container(color: Colors.blue, width: 100.0),
      new Container(color: Colors.red, width: 50.0,height: 50.0,),
      new Container(color: Colors.yellow, width: 150.0),
    ],
  ),
);

IntrinsicHeight例子

當沒有IntrinsicHeight包裹著,可以看到,第一三個Container高度是不受限制的,當外層套一個IntrinsicHeight,第一三個Container高度就調整到第二個一樣的高度。

3.5 源碼解析

構造函數如下:

const IntrinsicHeight({ Key key, Widget child })

3.5.1 屬性解析

除了child,沒有提供額外的屬性。

3.5.2 源碼

當child不為null的時候,具體的佈局代碼如下:

BoxConstraints childConstraints = constraints;
if (!childConstraints.hasTightHeight) {
  final double height = child.getMaxIntrinsicHeight(childConstraints.maxWidth);
  assert(height.isFinite);
  childConstraints = childConstraints.tighten(height: height);
}
child.layout(childConstraints, parentUsesSize: true);
size = child.size;

首先會檢測是否只有一個高度值滿足約束條件,如果不是的話,則返回一個最小的高度。然後調整尺寸。

3.6 使用場景

說老實話,不知道在什麼場景使用,可以替代的控制項也有的。谷歌說很有用,效率會有問題,建議一般的就別用了。

4. IntrinsicWidth

A widget that sizes its child to the child's intrinsic width.

4.1 簡介

IntrinsicWidth從描述看,跟IntrinsicHeight類似,一個是調整高度,一個是調整寬度。同樣是會存在效率問題,能別使用就儘量別使用。

4.2 佈局行為

IntrinsicWidth不同於IntrinsicHeight,它包含了額外的兩個參數,stepHeight以及stepWidth。而IntrinsicWidth的佈局行為跟這兩個參數相關。

  • 當stepWidth不是null的時候,child的寬度將會是stepWidth的倍數,當stepWidth值比child最小寬度小的時候,這個值不起作用;
  • 當stepWidth為null的時候,child的寬度是child的最小寬度;
  • 當stepHeight不為null的時候,效果跟stepWidth相同;
  • 當stepHeight為null的時候,高度取最大高度。

4.3 繼承關係

Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > IntrinsicWidth

4.4 示例代碼

new Container(
  color: Colors.green,
  padding: const EdgeInsets.all(5.0),
  child: new IntrinsicWidth(
    stepHeight: 450.0,
    stepWidth: 300.0,
    child: new Column(
      children: <Widget>[
        new Container(color: Colors.blue, height: 100.0),
        new Container(color: Colors.red, width: 150.0, height: 100.0),
        new Container(color: Colors.yellow, height: 150.0,),
      ],
    ),
  ),
)

IntrinsicWidth例子

分別對stepWidth以及stepHeight設置不同的值,可以看到不同的效果,當step值比最小寬高小的時候,這個值其實是不起作用的。感興趣的同學可以自己試試。

4.5 源碼解析

構造函數

const IntrinsicWidth({ Key key, this.stepWidth, this.stepHeight, Widget child })

4.5.1 屬性解析

stepWidth:可以為null,效果參看上面所說的佈局行為。

stepHeight:可以為null,效果參看上面所說的佈局行為。

4.5.2 源碼

我們先來看看佈局代碼中_applyStep函數

static double _applyStep(double input, double step) {
assert(input.isFinite);
if (step == null)
  return input;
return (input / step).ceil() * step;
}

如果存在step數值的話,則會是step的倍數,如果step為null,則返回原始的尺寸。

接下來我們看看child不為null時候的佈局代碼

BoxConstraints childConstraints = constraints;
if (!childConstraints.hasTightWidth) {
  final double width = child.getMaxIntrinsicWidth(childConstraints.maxHeight);
  assert(width.isFinite);
  childConstraints = childConstraints.tighten(width: _applyStep(width, _stepWidth));
}
if (_stepHeight != null) {
  final double height = child.getMaxIntrinsicHeight(childConstraints.maxWidth);
  assert(height.isFinite);
  childConstraints = childConstraints.tighten(height: _applyStep(height, _stepHeight));
}
child.layout(childConstraints, parentUsesSize: true);
size = child.size;

寬度方面的佈局跟IntrinsicHeight高度部分相似,只是多了一個step的額外數值。總體的佈局表現跟上面分析的佈局行為一致,根據step值是否是null來進行判斷,但是註意其對待高度與寬度的表現略有差異。

4.6 使用場景

這個控制項,說老實話,筆者還是不知道該在什麼場景下使用,可能會有些特殊的場景。但是從IntrinsicWidth與IntrinsicHeight佈局差異看,Flutter基礎控制項封的確實很隨性,一些可有可無甚至是重覆的控制項,我覺得精簡精簡挺好的,哈哈。

5. 後話

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

6. 參考

  1. Baseline class
  2. 基線
  3. FractionallySizedBox class
  4. IntrinsicHeight class
  5. IntrinsicWidth class

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

-Advertisement-
Play Games
更多相關文章
  • 一、常用的四種存儲引擎及其特點: (截圖摘自慕課網-與MySQL的零距離接觸-9.6節) 二、查看存儲引擎: 1. 查看MySQL提供的存儲引擎,通過命令 其中標註有DEFAULT關鍵字的存儲引擎為系統預設存儲引擎,如下圖所示: 2. 查看數據表的存儲引擎,使用命令 三、修改存儲引擎: 1. 修改M ...
  • 測試需求,id、姓名、郵箱、手機號不可重覆 1.創建序列 2.創建表 3.for迴圈插入數據 插入效果如下 ...
  • 源碼基於Android4.4 相關佈局文件的位置: frameworks/base/core/res目錄下: 1. notification_template_base.xml 2. notification_template_big_base.xml 3. notification_templat ...
  • 看了下公司的系統代碼對於根佈局decor_layout.xml的修改, 有所獲. 前些時候才開始做系統開發的時候, 總想改改系統的源碼, 至於原因: 人總是想裝裝, 在踩過幾個別人修改的坑後, 還是覺得在不改源碼的基礎上, 儘量納源碼為自己所用還是挺好的. 代碼如下: 該段代碼的核心, 就在上面的 ...
  • 前言 好久沒有寫破解教程了(我不會告訴你我太懶了),找到一款戀愛游戲,像我這樣的宅男只能玩玩戀愛游戲感覺一下戀愛的心動了。。 這款游戲免費試玩,但是後續章節得花6元錢購買,我怎麼會有錢呢,而且身在吾愛的大家庭里,不破解一波怎麼對得起我破解渣渣的身份呢! 喲,還是支付寶購買的,直接9000大法,但是破 ...
  • 編譯報錯 當你開心得升級完新 macOS,以及新 XCode,準備體驗了一把 Dark Mode 編程模式,開心的打開自己的老項目的時候,發現編譯不通過了╮(╯_╰)╭ 如果你的工程中如果依賴 libstdc++,無論是你本身的功能用 C++ 跨平臺編寫,還是你引入了某個 SDK 其內部依賴這個 l ...
  • 解決辦法,改為使用android-gif-drawable.jar來顯示gif圖片(需要配合com.android.support:support-v4:18.0.0使用) ...
  • 如果你是一個有經驗的 Android 程式員,那麼你肯定手寫過許多 以及 方法用來保持 Activity 的狀態,因為 Activity 在變為不可見以後,系統隨時可能把它回收用來釋放記憶體。 重寫 Activity 中的 方法 是 Google 推薦的用來保持 Activity 狀態的做法。 <! ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...