【布局 widget】Flutter Baseline

大家好,我是 17。

Baseline 是布局 widget,作用是让 child 的基线和指定的位置重合。Baseline 的布局逻辑不难,很多同学不知道如何用这个 widget 是因为对基线不是很理解。下面我们先看一下基线。

aa1.svg

基线(英语: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 套上一个红框,用来显示它的大小。

  1. baseline 与 child baseline 值相同

在本例中 child baseline 为 100,与指定的baseline 相同,结果是 size 与 child size 相同。Baseline紧紧包裹住 child。

非文字的基线位置是 box 的底部

  1. 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 底部

  1. baseline 可以为负值

baseline: 100 修改为 baseline: -10

size 为 0 child 在 Baseline 上方,和 Baseline 间隔 baseline 距离。

通过这样几个示例,我们对 Baseline 的作用已经有了感观上的认识。下面思考一下它的应用场景。

Baseline 的应用场景

通过上面的例子我们可以看出 Baseline 可以做溢出效果,但如果是溢出,最好还是用 OverflowBox。Baseline 的应用应该是在文字对齐方面。比如要实现下面的效果,"IAM17” 这几个字要求紧贴红框下边。

image.png

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。

猜你喜欢

转载自blog.csdn.net/m0_55635384/article/details/128929808