“這是我參與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 的對齊方向,可以通過 Alignment 或 AlignmentDirectional 進行調整所在位置;其中 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;
案例嘗試
小菜分如下幾個場景進行嘗試
- LimitedBox 父 Widget 無限制,子 Widget 寬高小於約束最大寬高;
return Container(child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 80, height: 80, color: Colors.purple.withOpacity(0.4))));
複製程式碼
- LimitedBox 父 Widget 無限制,子 Widget 寬高大於約束最大寬高;
return Container(child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 160, height: 160, color: Colors.orange.withOpacity(0.4))));
複製程式碼
- LimitedBox 父 Widget 有限制時;無論 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;
- BoxFit.fill 通過子 Widget 拉伸或壓縮填充滿父 Widget;
- BoxFit.contain 通過子 Widget 比例拉伸或壓縮,直到寬或高一邊填充父 Widget;
- BoxFit.cover 以子 Widget 寬或高填充父 Widget,剩餘一邊若超過父 Widget 對應邊則裁切;
- BoxFit.fitWidth 通過子 Widget 以寬為基準填充父 Widget,若高度超出會被裁切,子 Widget 不拉伸或壓縮;
- BoxFit.fitHeight 通過子 Widget 以高為基準填充父 Widget,若寬度超出會被裁切,子 Widget 不拉伸或壓縮;
- BoxFit.none 子 Widget 不拉伸或壓縮,若超出父 Widget 則被裁切;
- 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 的學習還不完整,有錯誤的地方請多多指導!
來源: 阿策小和尚