【Flutter 專題】67 圖解基本約束 Box (二)|8月更文挑戰

阿策小和尚發表於2021-08-21

      “這是我參與8月更文挑戰的第21天,活動詳情檢視: 8月更文挑戰” juejin.cn/post/698796…

      小菜繼續學習約束 Box 的各類應用;

UnconstrainedBox

原始碼分析

class UnconstrainedBox extends SingleChildRenderObjectWidget {
    const UnconstrainedBox({
        Key key,
        Widget child,
        this.textDirection,                 // 文字方向
        this.alignment = Alignment.center,  // 對齊方式
        this.constrainedAxis,               // 是否保留約束軸方向
    })
}
複製程式碼

      分析原始碼可得,UnconstrainedBox 繼承自 SingleChildRenderObjectWidget,與 ConstrainedBox 效果相反,給子 Widget 提供不加限制的空間;

案例嘗試

      UnconstrainedBox 不會對子 Widget 進行約束限制,按照其子 Widget 大小進行繪製;小菜理解為去除父 Widget 的限制,讓子 Widget 完全繪製;

1. alignment

      用於子 Widget 的對齊方向,可以通過 AlignmentAlignmentDirectional 進行調整所在位置;其中 AlignmentDirectional start/y 範圍是 [-1.0, 1.0]

2. textDirection

      當 alignment 使用 AlignmentDirectional 方式設定對齊方式時,textDirection 用於從左到右或從右到左的起始方向;

return Container(height: 180, width: 180, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(constrainedAxis: null,
        alignment: AlignmentDirectional(-1.0, 1.0), textDirection: TextDirection.ltr, 
        child: Container(width: 90, height: 90, color: Colors.green.withOpacity(0.6))));
return Container(height: 180, width: 180, color: Colors.redAccent.withOpacity(0.4),
    child: UnconstrainedBox(constrainedAxis: null,
        alignment: AlignmentDirectional(-1.0, -1.0), textDirection: TextDirection.rtl,
        child: Container(width: 100, height: 100, color: Colors.purple.withOpacity(0.6))));
複製程式碼

3. constrainedAxis

      作用於是否保留約束的軸方向,若不設定或設定為 null 則橫向或縱向均不保留約束;若設定為 vertical 則保留其父類縱向約束;設定為 horizontal 則保留其父類橫向約束;

return Container(height: 100, width: 360, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(alignment: Alignment.center, constrainedAxis: null,
        child: Container(width: 80, height: 80, color: Colors.green.withOpacity(0.6))));
return Container(height: 100, width: 360, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(alignment: Alignment.center, constrainedAxis: Axis.vertical,
        child: Container(width: 100, height: 300, color: Colors.green.withOpacity(0.6))));
return Container(height: 100, width: 360, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(alignment: Alignment.topRight, constrainedAxis: Axis.horizontal,
        child: Container(width: 100, height: 300, color: Colors.green.withOpacity(0.6))));
return Container(height: 100, width: 360, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(alignment: Alignment.topLeft, constrainedAxis: null,
        child: Container(width: 100, height: 300, color: Colors.green.withOpacity(0.6))));
複製程式碼

LimitedBox

原始碼分析

class LimitedBox extends SingleChildRenderObjectWidget {
  const LimitedBox({
    Key key,
    this.maxWidth = double.infinity,    // 最大寬度
    this.maxHeight = double.infinity,   // 最大高度
    Widget child,
  })
}
複製程式碼

      分析原始碼可知,LimitedBox 主要是在不受父 Widget 限制時,通過 maxHeight / maxWidth 對子 Widget 的約束,且 maxHeight / maxWidth 必須 >= 0.0;

案例嘗試

      小菜分如下幾個場景進行嘗試

  1. LimitedBoxWidget 無限制,子 Widget 寬高小於約束最大寬高;
return Container(child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 80, height: 80, color: Colors.purple.withOpacity(0.4))));
複製程式碼

  1. LimitedBoxWidget 無限制,子 Widget 寬高大於約束最大寬高;
return Container(child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 160, height: 160, color: Colors.orange.withOpacity(0.4))));
複製程式碼

  1. LimitedBoxWidget 有限制時;無論 LimitedBox 設定限制最大寬高和子 Widget 寬高,均以父 Widget 寬高為準;
return Container(width: 200, height: 80, child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 160, height: 160, color: Colors.orange.withOpacity(0.4))));
複製程式碼

FractionallySizedBox

原始碼分析

class FractionallySizedBox extends SingleChildRenderObjectWidget {
  const FractionallySizedBox({
    Key key,
    this.alignment = Alignment.center,  // 對齊方式
    this.widthFactor,                   // 寬度因子
    this.heightFactor,                  // 高度因子
    Widget child,
  })
}
複製程式碼

      分析原始碼可知,FractionallySizedBox 可以通過對齊方式和設定寬高因子並結合父 Widget 寬高來約束子 Widget;採用寬高因子使用更加靈活;

案例嘗試

1. alignment

      與其他元件相同,通用於子 Widget 的對齊方向;

2. widthFactor

      寬度因子,若不為 null 則通過父 Widget 寬度佔比來約束子 Widget 寬度;若為 null 按照父 Widget 寬度填充;

3. heightFactor

      高度因子,與 widthFactor 使用相同;

return Container(color: Colors.blueAccent.withOpacity(0.4), width: 100, height: 100,
    child: FractionallySizedBox(alignment: Alignment.center, widthFactor: 0.5, heightFactor: 0.5,
        child: Container(width: 50, height: 80, color: Colors.orange.withOpacity(0.6))));
return Container(color: Colors.blueAccent.withOpacity(0.4), width: 100, height: 100,
    child: FractionallySizedBox(alignment: Alignment.center, widthFactor: 0.5, heightFactor: null,
        child: Container(width: 200, height: 200, color: Colors.orange.withOpacity(0.6))));
return Container(color: Colors.blueAccent.withOpacity(0.4), width: 100, height: 100,
    child: FractionallySizedBox(alignment: Alignment.center, widthFactor: 1.5, heightFactor: 0.6,
        child: Container(color: Colors.orange.withOpacity(0.6))));
return Container(color: Colors.blueAccent.withOpacity(0.4), width: 100, height: 100,
    child: FractionallySizedBox(alignment: AlignmentDirectional(-0.15, -0.15), widthFactor: 0.5, heightFactor: 0.5,
        child: Container(color: Colors.orange.withOpacity(0.6))));
複製程式碼

FittedBox

原始碼分析

class FittedBox extends SingleChildRenderObjectWidget {
  const FittedBox({
    Key key,
    this.fit = BoxFit.contain,          // 填充方式
    this.alignment = Alignment.center,  // 對齊方式
    Widget child,
  })
}
複製程式碼

      分析原始碼可知,FittedBox 主要通過 fit 填充方式和 alignment 對齊方式對子 Widget 進行約束;且 fit / alignment 不可為空,對於圖片的裁剪很有效;

案例嘗試

      FittedBox 主要是通過 BoxFit 填充方式與 alignment 對齊方式共同約束子 Widget

  1. BoxFit.fill 通過子 Widget 拉伸或壓縮填充滿父 Widget
  2. BoxFit.contain 通過子 Widget 比例拉伸或壓縮,直到寬或高一邊填充父 Widget
  3. BoxFit.cover 以子 Widget 寬或高填充父 Widget,剩餘一邊若超過父 Widget 對應邊則裁切;
  4. BoxFit.fitWidth 通過子 Widget 以寬為基準填充父 Widget,若高度超出會被裁切,子 Widget 不拉伸或壓縮;
  5. BoxFit.fitHeight 通過子 Widget 以高為基準填充父 Widget,若寬度超出會被裁切,子 Widget 不拉伸或壓縮;
  6. BoxFit.noneWidget 不拉伸或壓縮,若超出父 Widget 則被裁切;
  7. BoxFit.scaleDown 若子 Widget 可以完全放在父 Widget 中則與 BoxFit.none 效果一致;若子 Widget 不能完全放在父 Widget 中則與 BoxFit.contain 效果一致;
return Container(width: 100, height: 100, color: Colors.blueAccent.withOpacity(0.4),
    child: FittedBox(fit: BoxFit.cover, alignment: Alignment.topCenter, child: Image.asset("images/icon_hzw02.jpg")));
return Container(width: 100, height: 100, color: Colors.blueAccent.withOpacity(0.4),
    child: FittedBox(fit: BoxFit.fill, alignment: Alignment.topCenter, child: Image.asset("images/icon_hzw02.jpg")));
return Container(width: 100, height: 100, color: Colors.blueAccent.withOpacity(0.4),
    child: FittedBox(fit: BoxFit.fitHeight, alignment: Alignment.topCenter, child: Image.asset("images/icon_hzw02.jpg")));
return Container(width: 100, height: 100, color: Colors.blueAccent.withOpacity(0.4),
    child: FittedBox(fit: BoxFit.none, alignment: Alignment.center, child: Image.asset("images/icon_hzw02.jpg")));
複製程式碼


      Flutter 提供了多種約束 Box 方式,基本都是繼承自 SingleChildRenderObjectWidget,每種 Box 有各自特點,合理利用可以大大提高開發效率;小菜對 Box 的學習還不完整,有錯誤的地方請多多指導!

來源: 阿策小和尚

相關文章