大家好,我是 17。
Baseline 是布局 widget,作用是让 child 的基线和指定的位置重合。Baseline 的布局逻辑不难,很多同学不知道如何用这个 widget 是因为对基线不是很理解。下面我们先看一下基线。
基线(英语:Baseline)指的是多数拉丁字母排列的基准线。如上图所示,大多字母都沿着红色基线排列。
baseline 理解了,但是 Baseline widget 还有一个参数 baselineType,这个参数是一枚举类型。
/// A horizontal line used for aligning text.
enum TextBaseline {
/// The horizontal line used to align the bottom of glyphs for alphabetic characters.
alphabetic,
/// The horizontal line used to align ideographic characters.
ideographic,
}
把注释翻译一下
// 一条用于对齐文本的水平线
enum TextBaseline {
/// 用于对齐字母字符字形底部的水平线
alphabetic,
/// 用于对齐表意字符的水平线
ideographic,
}
在英语中把中文,韩文等东亚文字称为 ideographic(表意)文字。比如 Fluter Widget 天天更新
这几个字放在一起的时候,基线就可以有两个 ,一个是 Fluter Widget
的基线,一个是 天天更新
的基线。
这样说了半天,可能还是不能理解,下面我们自己把这两条基线划出来。上面的是字母基线,下面的是表意基线
class myPainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
final textStyle = TextStyle(
color: Colors.black,
fontSize: 30,
);
final textSpan = TextSpan(
text: 'Flutter widget每日更新IAM17',
style: textStyle,
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout(
minWidth: 0,
maxWidth: size.width,
);
final paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 1;
// 把 TextBaseline.ideographic 改为 TextBaseline.alphabetic 画字母基线。
final distanceToBaseline =
textPainter.computeDistanceToActualBaseline(TextBaseline.ideographic);
canvas.drawLine(
Offset(0, distanceToBaseline),
Offset(textPainter.width, distanceToBaseline),
paint,
);
final offset = Offset(0, 0);
textPainter.paint(canvas, offset);
}
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
关于基线的知识了解了,Baseline 就变得非常简单了。
布局逻辑的代码
void performLayout() {
if (child != null) {
final BoxConstraints constraints = this.constraints;
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! as BoxParentData;
childParentData.offset = Offset(0.0, top);
final Size childSize = child!.size;
size =
constraints.constrain(Size(childSize.width, top + childSize.height));
} else {
size = constraints.smallest;
}
}
Baseline 就是让它指定的基线位置和 child 的基线重合。 我们通过示例看下。
Center(child:Container(
decoration: BoxDecoration(border: Border.all(color: Colors.red)),
child: Baseline(
baseline: 100,
baselineType: TextBaseline.ideographic,
child: Container(
width: 100,
height: 100,
color: Colors.blue[200],
))));
我们给 Baseline 套上一个红框,用来显示它的大小。
- baseline 与 child baseline 值相同
在本例中 child baseline 为 100,与指定的baseline 相同,结果是 size 与 child size 相同。Baseline紧紧包裹住 child。
非文字的基线位置是 box 的底部
- baseline 小于 child baseline
baseline: 100 修改为 baseline: 0
size 为0。chld 在 baseline 正上方。
3. baseline 大于 child baseline
baseline: 100 修改为 baseline: 150
size 为 150,Baseline 完全包裹 child。child 在 Baseline 底部
- baseline 可以为负值
baseline: 100 修改为 baseline: -10
size 为 0 child 在 Baseline 上方,和 Baseline 间隔 baseline 距离。
通过这样几个示例,我们对 Baseline 的作用已经有了感观上的认识。下面思考一下它的应用场景。
Baseline 的应用场景
通过上面的例子我们可以看出 Baseline 可以做溢出效果,但如果是溢出,最好还是用 OverflowBox。Baseline 的应用应该是在文字对齐方面。比如要实现下面的效果,"IAM17” 这几个字要求紧贴红框下边。
Container(
height: 50,
decoration: BoxDecoration(border: Border.all(color: Colors.red)),
child: Baseline(
baseline: 50,
baselineType: TextBaseline.ideographic,
child: Text('IAM17', style: TextStyle(fontSize: 24,)),
),
)
你可能会说,如果不贴底,可以设置一个偏移,但这个偏移是多少呢?随着字体,字号的变化,这个偏移量也是变化的。
用 Baseline 可以轻松实现基线对齐,遇到基线对齐的问题,应该第一时间想到 Baseline。