为了账号安全,请及时绑定邮箱和手机立即绑定

Flutter 32: 图解 TextPainter 与 TextSpan 小尝试

标签:
Android

      RichText 富文本核心即 TextSpan,而 TextSpan 结构很像 Android 中的 ViewGroup 树型结构。

webp

TextSpan 树形结构.png

webp

RichText 日常用法

      小菜理解为 RichText 是进阶版的 Text,如下直接看实例:

  1. TextDirection 用来控制文字位置,居左或居右边;当与 TextAlign 属性共存时,优先看整体,以 TextAlign 为准;

Widget richTextWid01() {  return RichText(
      text: TextSpan(
          text: 'TextDirection.ltr 文字默认居左',
          style: TextStyle(fontSize: 16.0, color: Colors.black)),
      textDirection: TextDirection.ltr);
}Widget richTextWid02() {  return RichText(
      text: TextSpan(
          text: 'TextDirection.rtl 文字默认居右',
          style: TextStyle(fontSize: 16.0, color: Colors.black)),
      textDirection: TextDirection.rtl);
}Widget richTextWid03() {  return RichText(
      text: TextSpan(
          text: 'textDirection 与 textAlign 同时设置,优先看整体,文字居中',
          style: TextStyle(fontSize: 16.0, color: Colors.black)),
      textDirection: TextDirection.rtl,
      textAlign: TextAlign.center);
}
  1. RichText 可以借助 TextSpan 实现文字的多种效果,小菜认为有点像文字效果拼接,每个 TextSpan 可以设置单独效果;

Widget richTextWid04() {  return RichText(
      text: TextSpan(
          text: '多种样式,如:',
          style: TextStyle(fontSize: 16.0, color: Colors.black),
          children: <TextSpan>[
            TextSpan(
                text: '红色',
                style: TextStyle(fontSize: 18.0, color: Colors.red)),
            TextSpan(
                text: '绿色',
                style: TextStyle(fontSize: 18.0, color: Colors.green)),
            TextSpan(
                text: '蓝色',
                style: TextStyle(fontSize: 18.0, color: Colors.blue)),
            TextSpan(
                text: '白色',
                style: TextStyle(fontSize: 18.0, color: Colors.white)),
            TextSpan(
                text: '紫色',
                style: TextStyle(fontSize: 18.0, color: Colors.purple)),
            TextSpan(
                text: '黑色',
                style: TextStyle(fontSize: 18.0, color: Colors.black))
          ]),
      textAlign: TextAlign.center);
}
  1. TextSpan 可以借助 recognizer 设置点击事件,包括点击/长按等;

final TapGestureRecognizer recognizer = TapGestureRecognizer();void initState() {  super.initState();
  recognizer.onTap = () {
    Toast.show('您好,欢迎点赞或关注!', context,
        duration: Toast.LENGTH_SHORT, gravity: Toast.BOTTOM);
  };
}Widget richTextWid05() {  return RichText(
      text: TextSpan(
          text: 'recognizer 为手势识别者,可设置点击事件,',
          style: TextStyle(fontSize: 17.0, color: Colors.black),
          children: <TextSpan>[
        TextSpan(
            text: '点我试试',
            style: TextStyle(fontSize: 17.0, color: Colors.blue),
            recognizer: recognizer)
      ]));
}

TextPainter 日常用法

      RichText 的使用很方便,但如果在深入了解 TextSpan 就有很多趣味了;Flutter 提供了和 Android 类似的 Canvas 绘制方法,但是 Canvas 却不支持 drawText,如果想要实现绘制文字,就需要 TextPainter 而其内部主要是由 TextSpan 实现。

      使用 TextPainter 时需要继承 CustomPainter,并实现 paintshouldRepaint 方法,主要是在 paint 中进行绘制 TextPainter。与 RichText 功能相同,可以完全实现 RichText 效果;

      TextPainter 绘制需要实现 layoutpaint 方法,即绘制位置与绘制范围。

  1. TextDirectionTextAlign 效果与 RichText 一致,但是 TextPainter 绘制时需要设置 layout 的最大最小范围,而此时,文字位置与 layout 有关;当文字长度小于设置的 minWidth 最小宽度时,以 minWidth 宽度为限制居左/居右/居中等;而当文字长度大于设置的 minWidth 最小宽度时,以 maxWidth 最大宽度为限制,包括换行等;

TextPainter(
    text: TextSpan(
        text: 'TextDirection.ltr 文字默认居左',
        style: TextStyle(fontSize: 16.0, color: Colors.black)),
    textDirection: TextDirection.ltr)
  ..layout(maxWidth: Screen.width, minWidth: Screen.width)
  ..paint(canvas, Offset(0.0, 0.0));
TextPainter(
    text: TextSpan(
        text: 'TextDirection.rtl 文字默认居右',
        style: TextStyle(fontSize: 16.0, color: Colors.black)),
    textDirection: TextDirection.rtl)
  ..layout(maxWidth: Screen.width, minWidth: Screen.width)
  ..paint(canvas, Offset(0.0, 24.0));
TextPainter(
    text: TextSpan(
        text: 'textDirection 与 textAlign 同时设置,优先看整体,文字居中',
        style: TextStyle(fontSize: 16.0, color: Colors.black)),
    textDirection: TextDirection.rtl,
    textAlign: TextAlign.center)
  ..layout(maxWidth: Screen.width, minWidth: Screen.width)
  ..paint(canvas, Offset(0.0, 48.0));
TextPainter(
    text: TextSpan(
        text: '文字位置与 layout 的最大最小宽度有关',
        style: TextStyle(fontSize: 16.0, color: Colors.black)),
    textDirection: TextDirection.rtl)
  ..layout(maxWidth: Screen.width - 100.0, minWidth: Screen.width - 200.0)
  ..paint(canvas, Offset(0.0, 90.0));
TextPainter(
    text: TextSpan(
        text: '文字长度较小',
        style: TextStyle(fontSize: 16.0, color: Colors.black)),
    textDirection: TextDirection.rtl)
  ..layout(maxWidth: Screen.width - 100.0, minWidth: Screen.width - 140.0)
  ..paint(canvas, Offset(0.0, 124.0));
  1. 而对于绘制多效果的样式也是很方便,与 RichText 基本一致;

TextPainter(
    text: TextSpan(
        text: '多种样式,如:',
        style: TextStyle(fontSize: 16.0, color: Colors.black),
        children: <TextSpan>[
          TextSpan(
              text: '红色',
              style: TextStyle(fontSize: 18.0, color: Colors.red)),
          TextSpan(
              text: '绿色',
              style: TextStyle(fontSize: 18.0, color: Colors.green)),
          TextSpan(
              text: '蓝色',
              style: TextStyle(fontSize: 18.0, color: Colors.blue)),
          TextSpan(
              text: '白色',
              style: TextStyle(fontSize: 18.0, color: Colors.white)),
          TextSpan(
              text: '\n紫色',
              style: TextStyle(fontSize: 18.0, color: Colors.purple)),
          TextSpan(
              text: '黑色',
              style: TextStyle(fontSize: 18.0, color: Colors.black))
        ]),
    textDirection: TextDirection.ltr,
    textAlign: TextAlign.center)
  ..layout(maxWidth: Screen.width, minWidth: Screen.width)
  ..paint(canvas, Offset(0.0, 148.0));
  1. 小菜一直有问题的就是设置点击事件,小菜以为与 RichText 一样直接传递 recognizer 即可,但始终无法调起,希望有解决过这个问题的朋友多多指导,如下是小菜的测试代码;

TextPainter(
    text: TextSpan(
        text: 'recognizer 为手势识别者,可设置点击事件,',
        style: TextStyle(fontSize: 17.0, color: Colors.black),
        children: <TextSpan>[
          TextSpan(
              text: '测试暂时有误,待研究',
              style: TextStyle(fontSize: 17.0, color: Colors.blue))
        ],
        recognizer: TapGestureRecognizer()
          ..onTap = () {            print('===测试暂时有误,待研究==');
          }),
    textDirection: TextDirection.ltr,
    textAlign: TextAlign.center)
  ..layout(maxWidth: Screen.width - 40.0, minWidth: Screen.width - 40.0)
  ..paint(canvas, Offset(20.0, 200.0));
  1. 小菜认为最有意思的就是 TextSpanstyleheight 属性,在 TextSpan 中此值设置行高,是以文字基准线为最小距离;

TextPainter(
    text: TextSpan(
        text: 'TextPainter 小尝试',
        style: TextStyle(fontSize: 20.0, color: Colors.black54),
        children: <TextSpan>[
          TextSpan(
              text: '\n作者:和尚(height:1.6)',
              style: TextStyle(
                  fontSize: 14.0, color: Colors.black54, height: 1.6))
        ]),
    textDirection: TextDirection.ltr,
    textAlign: TextAlign.center)
  ..layout(maxWidth: Screen.width, minWidth: Screen.width)
  ..paint(canvas, Offset(0.0, 20.0));
TextPainter(
    text: TextSpan(
        text: 'TextPainter 小尝试',
        style: TextStyle(fontSize: 20.0, color: Colors.black54),
        children: <TextSpan>[
          TextSpan(
              text: '\n作者:和尚(height:3.0)',
              style: TextStyle(
                  fontSize: 14.0, color: Colors.black54, height: 3.0))
        ]),
    textDirection: TextDirection.ltr,
    textAlign: TextAlign.center)
  ..layout(maxWidth: Screen.width, minWidth: Screen.width)
  ..paint(canvas, Offset(0.0, 90.0));
TextPainter(
    text: TextSpan(
        text: 'TextPainter 小尝试(height:0.1)',
        style:
            TextStyle(fontSize: 20.0, color: Colors.black54, height: 0.1),
        children: <TextSpan>[
          TextSpan(
              text: '\nTextPainter 小尝试(height:0.1)',
              style: TextStyle(
                  fontSize: 20.0, color: Colors.black54, height: 0.1)),
          TextSpan(
              text: '\nTextPainter 小尝试(height:0.1)',
              style: TextStyle(
                  fontSize: 20.0, color: Colors.black54, height: 0.1))
        ]),
    textDirection: TextDirection.ltr,
    textAlign: TextAlign.center)
  ..layout(maxWidth: Screen.width, minWidth: Screen.width)
  ..paint(canvas, Offset(0.0, 220.0));



作者:阿策神奇
链接:https://www.jianshu.com/p/0fd1eaea6269


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消