2.1.3 RichText
RichText组件可用来显示一段包含不同样式的文本。一般而言,Text组件足以满足大部分文本显示的需求,配合style等参数,Text组件也能渲染出各式各样的颜色、字体、字号、粗细、阴影等特效,但实战中偶尔会需要改变一段文字中的几个字,例如加粗强调一个词,或者为其中几个字添加蓝色下画线,制造出可以单击的视觉效果等。此时使用RichText组件就可以方便地在不同样式之间切换。
1. text属性
RichText组件中需要显示的文本内容由text属性设置。不同于Text组件,这里RichText组件需要传入的文本信息不是简单的字符串(String)类型,而是TextSpan类型。
TextSpan类型本身是一种可以无限递归的树状结构。每个节点除了可以通过text属性传入字符串外,还可以通过style属性自定义文字样式,甚至可以再通过children属性传入一个TextSpan列表作为子节点,以实现叠加和嵌套文字样式的功能。
例如,可使用RichText渲染《桃花源记》的第一段,并多次切换文本样式,代码如下:
以上这段代码多次调用TextSpan,递归出如图2-15所示的树状结构。其中,每个TextSpan都支持设定文本内容(text参数)和文本样式(style参数),两者均为选填。
图2-15 TextSpan的树状递归结构
若text属性不为空,则这里的字符串会被插入最终文本内容中。若为空,程序运行时则会继续搜索子级TextSpan。最终内容生成遵循深度优先遍历顺序。
若style属性不为空,则上级继承的样式将与当前样式合并,并应用到当前TextSpan及全部的下级TextSpan。若style为空,则直接继承上级的样式而不做修改。本例中,树根级的TextSpan中设置的18号黑色将作用于所有的TextSpan。
图2-16 RichText可在不同样式之间切换
例如,本例中负责渲染“落英缤纷”片段的TextSpan,就运用了自身“下画波浪线”样式,并继承了父级中的“斜体”样式,而其父级本身也继承了更上级“18号黑色”样式。由于之后的句号不需要加下画线,因此单独作为另一个TextSpan放在同级。本例最终运行效果如图2-16所示。
2. Text组件的Text.rich()构造函数
不同于之前介绍的Text组件,这里通过text参数传给RichText组件的TextSpan类型只会继承上级TextSpan树中的样式,而不继承上级DefaultTextStyle组件提供的默认样式。如需使用DefaultTextStyle组件统一设置样式,则可以考虑使用Text组件的Text.rich()构造函数。
Text.rich()同样需要传入TextSpan树,因此与RichText用法大同小异。
例如,在之前《桃花源记》的例子中,源代码开头部分如下:
这里只需修改前两句代码便可以完成RichText组件到Text组件的切换。替换之后的代码如下:
切换到Text组件后,就可以用DefaultTextStyle组件统一设置多个Text组件的风格了。具体用法可参考本章前面关于DefaultTextStyle组件的介绍及代码示例。
值得一提的是,即使在实战中不需要在父级中插入DefaultTextStyle组件统一设置样式,通常开发者依然倾向于选用Text.rich()构造函数继承Flutter框架已有的文本样式,如Material风格等。例如,一般App项目中的默认文本颜色很可能是黑色,但前文也提到过,TextStyle的默认文本颜色是白色,因此读者可在简单的对比实验后发现,用Text组件通常不需要额外设置文本颜色,但用RichText组件则经常需要手动设置文本颜色。如上述《桃花源记》的例子中,改用Text.rich()后,第1个TextSpan的color:Colors. black参数可被省略。
3.其他属性
除了text属性外,RichText组件还同样支持Text组件的部分其他属性,如textAlign属性可以用于设置文本对齐方式,maxLines和overflow等可以规定最大行数及溢出部分的处理方式,textScaleFactor可以决定放大系数等。对此不熟悉的读者可参考本章介绍Text组件的相关内容及代码示例。
4.触碰检测
实战中经常会遇到需要给一段文字中的某些部分加入链接,因此可能需要在某段文字中加入用户单击(触碰)的检测。TextSpan中的recognizer参数支持传入一个GestureRecognizer类以便完成TextSpan树中某一片段的检测。例如,可利用5个TextSpan完成对其中2块区域的检测,代码如下:
程序运行效果如图2-17所示。
图2-17 RichText同时实现2个链接的效果
这里使用TextSpan配合recognizer的这种检测用户单击的方式比较烦琐。实战中若可以检测整个RichText组件或Text组件的触碰事件(而不需要单独检测其中几个字或单词)时,更推荐直接使用一个名为GestureDetector的常用组件,具体用法可参考第8章“人机交互”的相关内容。