OverflowBox 和 SizedOverflowBox 允许子控件超出父控件的边界。这个特性可以用来实现一些比较棘手的视觉效果。
设计给出如下视觉图:

初看觉得没有什么特别的,不过是7个控件平均水平分布。但仔细观察之后发现并非如此:其中一个控件(表示当天,称之A控件)的背景比较特别,超出边框范围带一点光晕效果。这个光晕背景其实比其他控件(表示非当天,称之B控件)的背景占据的空间要大。
方案一 - “理想的背景图”
控件A和控件B的背景大小不一致,且要求水平方向平均分布。一种可行的方式是使用实际上大小相同、但视觉上有差异的背景图,比如控件A使用 100x100带光晕效果的背景图,控件B使用 100x100的透明背景图。可惜我们视觉未给出这种理想的背景图
方案二 - “聪明的边距”
既然控件A和控件B的背景大小不一致,又要求水平方向平均分布。如果没有”理想的背景图”,我们还可以想办法:
- 让控件A和控件B大小不一致(以达到视觉上”看起来”大小一致的效果)
- 添加不同大小的边距(padding 或 margin)让它们”看起来”水平平均分布
不过添加”聪明的边距”的代码会惨不忍睹,几乎没有可维护性。
方案三 - OverflowBox 和 SizedOverflowBox
看如何使用 SizedOverflowBox 来解决这个问题。
优化前
优化前,光晕背景图无法占满控件A,视觉效果不佳。

控件A代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @override Widget build(BuildContext context) { return Container( width: 36, height: 36, decoration: BoxDecoration( border: Border.all( width: 1, color: c_FFFFE1A6, ), borderRadius: BorderRadius.all(Radius.circular(3)), image: DecorationImage( image: AssetImage(_bgAwardToday), fit: BoxFit.fitHeight)), child: child, alignment: Alignment.center, ); }
|
优化后
优化后,光晕背景图可以占满控件A,完美还原视觉图。

此外,控件A的大小为 (width=36.0, height=36.0),与控件B的大小完全一致。由于控件A和控件B的大小一致,所以让它们水平方向平均分布的代码非常简单优雅,spaceBetween
即可。
1 2 3
| Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [] )
|
控件A代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @override Widget build(BuildContext context) { return SizedOverflowBox( size: const Size(36.0, 36.0), child: Stack(alignment: Alignment.center, children: [ Image.asset( _bgAwardToday, width: 56, ), SizedBox( child: child, width: 36, height: 36, ), ]), alignment: Alignment.center, ); }
|
以下是控件B的代码。用于对照参考。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @override Widget build(BuildContext context) { return Container( width: 36, height: 36, decoration: BoxDecoration( border: Border.all( width: 1, color: Color(0X62FFFFFF), ), borderRadius: BorderRadius.all(Radius.circular(3)), image: DecorationImage(image: AssetImage(_bgAwardOthers))), child: child, alignment: Alignment.center, ); }
|
SliceSizedOverflowBox 介绍
TODO
参考
如下,蓝色矩形子控件超出了浅蓝色矩形父控件的区域。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class SliceSizedOverflowBox extends StatelessWidget implements SliceExample { @override String get name => 'SliceSizedOverflowBox';
@override Widget build(BuildContext context) { return Container( color: Colors.blue[50], child: SizedOverflowBox( size: const Size(100.0, 100.0), alignment: AlignmentDirectional.bottomStart, child: Container(height: 50.0, width: 150.0, color: Colors.blue,), ), ); } }
|