??????大家在學(xué)習(xí) Flutter 時一定會用過 Text委刘,而對于一些復(fù)雜文本的處理可能會選擇 RichText像街,再進(jìn)一步规辱,使用 RichText 就一定要用 TextSpan ,小菜本以為可以做為一個小知識點進(jìn)行簡單學(xué)習(xí)赛糟,但是隨著深入嘗試發(fā)現(xiàn) TextSpan 涉及東西很多,很值得研究晒他,因此單獨整理一篇小博文。
??????RichText 富文本核心即 TextSpan逸贾,而 TextSpan 結(jié)構(gòu)很像 Android 中的 ViewGroup 樹型結(jié)構(gòu)陨仅。
RichText 日常用法
??????小菜理解為 RichText 是進(jìn)階版的 Text津滞,如下直接看實例:
- TextDirection 用來控制文字位置,居左或居右邊灼伤;當(dāng)與 TextAlign 屬性共存時触徐,優(yōu)先看整體,以 TextAlign 為準(zhǔn)狐赡;
Widget richTextWid01() {
return RichText(
text: TextSpan(
text: 'TextDirection.ltr 文字默認(rèn)居左',
style: TextStyle(fontSize: 16.0, color: Colors.black)),
textDirection: TextDirection.ltr);
}
Widget richTextWid02() {
return RichText(
text: TextSpan(
text: 'TextDirection.rtl 文字默認(rèn)居右',
style: TextStyle(fontSize: 16.0, color: Colors.black)),
textDirection: TextDirection.rtl);
}
Widget richTextWid03() {
return RichText(
text: TextSpan(
text: 'textDirection 與 textAlign 同時設(shè)置撞鹉,優(yōu)先看整體,文字居中',
style: TextStyle(fontSize: 16.0, color: Colors.black)),
textDirection: TextDirection.rtl,
textAlign: TextAlign.center);
}
- RichText 可以借助 TextSpan 實現(xiàn)文字的多種效果颖侄,小菜認(rèn)為有點像文字效果拼接鸟雏,每個 TextSpan 可以設(shè)置單獨效果;
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: '藍(lán)色',
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);
}
- TextSpan 可以借助 recognizer 設(shè)置點擊事件孝鹊,包括點擊/長按等;
final TapGestureRecognizer recognizer = TapGestureRecognizer();
void initState() {
super.initState();
recognizer.onTap = () {
Toast.show('您好展蒂,歡迎點贊或關(guān)注!', context,
duration: Toast.LENGTH_SHORT, gravity: Toast.BOTTOM);
};
}
Widget richTextWid05() {
return RichText(
text: TextSpan(
text: 'recognizer 為手勢識別者又活,可設(shè)置點擊事件,',
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松捉,如果想要實現(xiàn)繪制文字夹界,就需要 TextPainter 而其內(nèi)部主要是由 TextSpan 實現(xiàn)。
??????使用 TextPainter 時需要繼承 CustomPainter隘世,并實現(xiàn) paint 和 shouldRepaint 方法可柿,主要是在 paint 中進(jìn)行繪制 TextPainter。與 RichText 功能相同丙者,可以完全實現(xiàn) RichText 效果复斥;
??????TextPainter 繪制需要實現(xiàn) layout 與 paint 方法,即繪制位置與繪制范圍械媒。
- TextDirection 和 TextAlign 效果與 RichText 一致目锭,但是 TextPainter 繪制時需要設(shè)置 layout 的最大最小范圍,而此時纷捞,文字位置與 layout 有關(guān)痢虹;當(dāng)文字長度小于設(shè)置的 minWidth 最小寬度時,以 minWidth 寬度為限制居左/居右/居中等主儡;而當(dāng)文字長度大于設(shè)置的 minWidth 最小寬度時奖唯,以 maxWidth 最大寬度為限制,包括換行等糜值;
TextPainter(
text: TextSpan(
text: 'TextDirection.ltr 文字默認(rèn)居左',
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 文字默認(rèn)居右',
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 同時設(shè)置丰捷,優(yōu)先看整體坯墨,文字居中',
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 的最大最小寬度有關(guān)',
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));
- 而對于繪制多效果的樣式也是很方便,與 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: '藍(lán)色',
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));
- 小菜一直有問題的就是設(shè)置點擊事件,小菜以為與 RichText 一樣直接傳遞 recognizer 即可停巷,但始終無法調(diào)起耍攘,希望有解決過這個問題的朋友多多指導(dǎo),如下是小菜的測試代碼叠穆;
TextPainter(
text: TextSpan(
text: 'recognizer 為手勢識別者少漆,可設(shè)置點擊事件,',
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));
- 小菜認(rèn)為最有意思的就是 TextSpan 中 style 的 height 屬性,在 TextSpan 中此值設(shè)置行高嚷硫,是以文字基準(zhǔn)線為最小距離检访;
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));
??????如果有不對的地方還希望多多指出。
來源:阿策小和尚