Flutter 中 RichText、SelectableText 的使用详解 | Flutter Widgets

这是我参与更文挑战的第25天,活动详情查看: 更文挑战html

前言

前面咱们聊了 Flutter 中 Text 各类属性样式调配的展现效果,这篇咱们稍微深刻一点,看看 Text 的源码以及富文本的使用,最后聊聊选择文本的应用。git

image.png

RichText

Text 源码

查看富文本以前,咱们先看看上篇的 Text 源码,其实在上上篇咱们演示行高参数的时候就能够看到虽然咱们使用的是 Text ,可是渲染时在 Widget 树中看到的是 RichText
image.pnggithub

Text 源码一览

出现上述的缘由是什么呢?咱们来瞅瞅源码吧
image.png
首先 Text 继承自 StatelessWidget ,下面咱们就直接看 build 方法便可。api

这里看到上面注释圈起来的部分,说 RichText 能够更好的让咱们控制文字样式markdown

  • Text - build 方法

image.png
上面👆🏻能够看出 build 方法最终返回的是 result (550 行),而 result 建立的就是 RichText 对象,通常咱们没有给文字添加语义标签 semanticsLabel ,因此就会直接返回 RichText Widget 了。less

如今咱们就知道为啥咱们写的是 Text ,但实际是 RichText 的 Widget 的缘由了ide

简单富文本

上面咱们知道了缘由,下面咱们就从一个简单的富文原本走进 RichText
image.png
👆🏻上面的效果,若是单独使用 Text 写是否是咱们要外部嵌套一个 Row+3个Text , 咱们还要考虑换行问题,这样就比较麻烦了,若是咱们使用 RichText,就不须要考虑这么多,关心样式便可。oop

RichText(
  text: TextSpan(
    text: 'Flutter Widgets 已有 ',
    children: [
      TextSpan(
        text: '25',
        // 设置个性化覆盖样式
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 18,
        ),
      ),
      // 复用上层通用样式
      TextSpan(text: ' 系列文章'),
    ],
    // 设置通用样式
    style: TextStyle(
      color: Colors.blue,
    ),
  ),
)
复制代码

这里咱们主要关心样式的设置,有 2 个点须要注意:post

  • 思想上要理解好这种 TextSpan 的嵌套关系
  • 要理解 style 的继承和覆盖关系

TextSpan

上面咱们使用到了 TextSpan ,来一块儿看看他的属性吧。ui

上源码

image.png
这里咱们看到 TextSpan 继承自 InlineSpan ,实现了 HitTestTarget(命中检测)和 MouseTrackerAnnotation (鼠标追踪),属性上也很是的简单,经常使用的可能就是前 4 个,而后前 3 个咱们都了解使用过了,下面来看看第四个吧。

局部手势检测

我如今把 25 这个数字变成红色,而且要加上点击事件怎么办呢?这时候就用到了第 4 个属性 recognizer

// 点击手势检测器
late TapGestureRecognizer tapRecognizer;
@override
void initState() {
  tapRecognizer = TapGestureRecognizer()..onTap = _handleTap;
  super.initState();
}

/// 处理点击
void _handleTap() {
  // 打印
  print('tapRecognizer 25');
  // 设置震动效果
  HapticFeedback.vibrate();
}
// 这里只贴图 25 的部分代码
TextSpan(
  text: '25',
  // 设置个性化覆盖样式
  style: TextStyle(
    fontWeight: FontWeight.bold,
    fontSize: 18,
    color: Colors.red,
  ),
  // 设置点击检测器
  recognizer: tapRecognizer,
)
复制代码
  • 显示效果

image.png

  • 点击后打印以下

image.png
这样咱们再作,好比用户协议与隐私政策的时候就能够用到啦,能够作单独的样式和跳转。

WidgetSpan

上面咱们还只是说了富文本中文字多样式的状况,还有嵌套各类图片的状况,在实际富文本应用时比这个要复杂的多,文章中示例作核心的解法,具体还须要实际应用和创新。
image.png
若是在上面的基础上咱们须要加上图标怎么处理呢?看看下面的代码

RichText(
  text: TextSpan(
    children: [
      // Flutter Logo
      WidgetSpan(child: FlutterLogo()),
      TextSpan(text: 'Flutter Widgets 已有 '),
      TextSpan(
        text: '25',
        // 设置个性化覆盖样式
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 18,
          color: Colors.red,
        ),
        recognizer: tapRecognizer,
      ),
      // 连接图标
      WidgetSpan(
        child: Icon(
          Icons.link,
          size: 16,
          color: Colors.blue,
        ),
      ),
      // 复用上层通用样式
      TextSpan(text: ' 系列文章'),
      // 复制图标
      WidgetSpan(
        child: Icon(
          Icons.copy,
          size: 16,
          color: Colors.grey,
        ),
      ),
    ],
    // 设置通用样式
    style: TextStyle(
      color: Colors.blue,
    ),
  ),
)
复制代码

这里只是演示,实际项目中会根据下发的文本协议来解析,而后生成对应的 Widget 组合

Text.rich

另一种建立富文本的方式就是使用 Text.rich ,下面来一块儿看看代码吧

Text.rich(
  TextSpan(
    children: [
      WidgetSpan(child: FlutterLogo()),
      TextSpan(text: 'Flutter Widgets 已有 '),
      TextSpan(
        text: '25',
        // 设置个性化覆盖样式
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 18,
          color: Colors.red,
        ),
        recognizer: tapRecognizer,
      ),
      WidgetSpan(
        child: Icon(
          Icons.link,
          size: 16,
          color: Colors.blue,
        ),
      ),
      // 复用上层通用样式
      TextSpan(text: ' 系列文章'),
      WidgetSpan(
        child: Icon(
          Icons.copy,
          size: 16,
          color: Colors.grey,
        ),
      ),
    ],
    // 设置通用样式
    style: TextStyle(
      color: Colors.blue,
    ),
  ),
)
复制代码

image.png

小总结

到这里 RichText 基本就聊完了,基础的样式咱们在前 2 篇文章已经聊过,能够在专栏中回看。

SelectableText

上面展现的文本都是没法选择复制的,在实际项目中,有些内容文字是须要支持用户能够选择复制的,这时咱们就须要将 Text 改变成 SelectableText
image.png

代码展现

SelectableText(
  "Text - ZeroFlutter",
  style: TextStyle(
    // 颜色蓝色
    color: Colors.blue,
    // 字号 24
    fontSize: 24,
  ),
)
复制代码

使用限制

在实际使用时,你会发现没法指定溢出样式了,默认就是直接剪裁掉了。
image.png
由于考虑到,复制确定是对全部文本进行操做,若是咱们溢出样式是... 那么复制出来就是展现的样式,确定不符合需求。
因此在实际项目中,若是是长按复制所有可使用 Text ,选择复制能够 SelectableText

SelectableText.rich

Text.rich 一致,要使用富文本时,能够直接使用 SelectableText.rich

可是这里有个显示就是咱们不能使用 WidgetSpan 了,只能使用 TextSpan

SelectableText.rich(
  TextSpan(
    children: [
      // WidgetSpan(child: FlutterLogo()),
      TextSpan(text: 'Flutter Widgets 已有 '),
      TextSpan(
        text: '25',
        // 设置个性化覆盖样式
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 18,
          color: Colors.red,
        ),
        recognizer: tapRecognizer,
      ),
      // WidgetSpan(
      // child: Icon(
      // Icons.link,
      // size: 16,
      // color: Colors.blue,
      // ),
      // ),
      // 复用上层通用样式
      TextSpan(text: ' 系列文章'),
      // WidgetSpan(
      // child: Icon(
      // Icons.copy,
      // size: 16,
      // color: Colors.grey,
      // ),
      // ),
    ],
    // 设置通用样式
    style: TextStyle(
      color: Colors.blue,
    ),
  ),
)
复制代码

image.png

源码仓库

基于 Flutter 🔥 最新版本

参考连接

关注专栏

  • 此文章已收录到下面👇 的专栏,能够直接关注
  • 更多文章继续阅读|系列文章持续更新

👏 欢迎点赞➕收藏➕关注,有任何问题随时在下面👇评论,我会第一时间回复哦

相关文章
相关标签/搜索