本文主要介绍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,可以看下下面这张图,这具体就涉及到了字体排版,感兴趣的同学可以自行了解。
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的布局行为。
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数值的,存在的话,就取这个值,不存在的话,则取其高度。
整体的计算过程:
- 获取child的 baseline 值;
- 计算出top值,其为 baseline - childBaseline,这个值有可能为负数;
- 计算出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,
),
),
)
运行效果如下所示
2.5 源码解析
const FractionallySizedBox({
Key key,
this.alignment = Alignment.center,
this.widthFactor,
this.heigh