Flutter 32: 圖解 TextPainter 與 TextSp

westwolf發表於2021-09-09

      RichText 富文字核心即 TextSpan,而 TextSpan 結構很像 Android 中的 ViewGroup 樹型結構。

圖片描述

TextSpan 樹形結構.png

圖片描述

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,如果想要實現繪製文字,就需要 而其內部主要是由 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));



作者:阿策神奇
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4662/viewspace-2822124/,如需轉載,請註明出處,否則將追究法律責任。

相關文章