Flutter 实现不同样式(有样式) 的TextField (可自定义),类似微博#话题#、@用户,(给TextField加TextSpan)

  • 2020 年 3 月 27 日
  • 笔记

描述

先上效果图

在项目中,有 @ 和 话题功能,需要在编辑时即可回显,但是官方原生的TextField不支持对部分文字定义不同的样式,所以封装了一个。

注意:这不是富文本插件,不支持在输入框中显示图片,仅是 TextField 的扩展,让其支持自定义 TextSpan。

本文介绍封装思路,如果想要直接在项目中应用,可以直接通过以下方式引入:

插件地址:https://pub.dev/packages/text_span_field

text_span_field: 1.0.0  

使用方式为:

TextSpanField(      controller: TextEditingController(        text: "这是一条测试信息,你们看他的颜色",      ),      rangeStyles: [        RangeStyle(          range: TextRange(start: 0, end: 1),          style: TextStyle(color: Color(0xFF5BA2FF)),        ),        RangeStyle(          range: TextRange(start: 3, end: 4),          style: TextStyle(color: Color(0xFF9C7BFF)),        ),      ],  ),

 

正文

项目地址:https://github.com/JiangJuHong/FlutterTextSpanField

项目结构:

首先,我们要在TextField中进行扩展,必要的查看源代码,直接跳转到 build 渲染,发现代码如下:

 

 

 TextField内部使用的是EditableText,在Flutter官网介绍如如下:

 

 

 “基本文本输入域”

EditableText 组件内部有一个可重写方法 buildTextSpan,它定义了内容如何展示在输入框中,默认未经过处理,我们需要展示不同的内容,则需要重写该方法并根据要求进行封装。

第一步:继承 EditableText 并重写 buildTextSpan 属性

因此我们创建一个名叫 “EditableTextSpan”的组件,并继承了EditableText,然后重写了buildTextSpan,经过重写的代码如下:

代码地址:https://github.com/JiangJuHong/FlutterTextSpanField/blob/master/lib/editable_text_span.dart

 

 

其中 rangeStyle 为自定义范围样式类,方便组件使用时传递,rangeStyle代码为:

 1 import 'package:flutter/cupertino.dart';   2   3 /// 范围样式,规定不同范围不同样式   4 class RangeStyle extends Comparable<RangeStyle> {   5   RangeStyle({@required this.range, this.style});   6   7   /// 范围   8   final TextRange range;   9  10   /// 指定样式  11   final TextStyle style;  12  13   @override  14   int compareTo(RangeStyle other) {  15     return range.start.compareTo(other.range.start);  16   }  17  18   @override  19   String toString() {  20     return 'RangeStyle(range:$range, style:$style)';  21   }  22 }

代码地址:https://github.com/JiangJuHong/FlutterTextSpanField/blob/master/lib/range_style.dart

重写的 buildTextSpan 中主要的业务逻辑为根据 TextRange 定义的范围,应用不同的 TextStyle

第二步:重新封装TextField

buildTextSpan重写完毕后,默认的TextField并不会使用我们重写过后的文件,所以我们需要进行如下步骤操作:

1. 将 TextField的文件拷贝出来后命名为TextSpanField,随后将 build 方法中的EditableText 替换成EditableTextSpan。

 

2. 在 TextSpanField 中公开 rangeStyle 属性,并传递给 EditabledTextSpan

代码地址:https://github.com/JiangJuHong/FlutterTextSpanField/blob/master/lib/text_span_field.dart

结束

到这一步,我们组件已经封装完成,可以实现对不同的范围渲染不同的样式。

使用方法:

TextSpanField(      controller: TextEditingController(        text: "这是一条测试信息,你们看他的颜色",      ),      rangeStyles: [        RangeStyle(          range: TextRange(start: 0, end: 1),          style: TextStyle(color: Color(0xFF5BA2FF)),        ),        RangeStyle(          range: TextRange(start: 3, end: 4),          style: TextStyle(color: Color(0xFF9C7BFF)),        ),      ],  ),  

  

由于本文章并未精准讲解每一行代码,可能需要结合源代码一起研究,源代码地址为:https://github.com/JiangJuHong/FlutterTextSpanField/tree/master/lib

该内容已封装为插件 text_span_field ,由于并未对原生内容进行改动,所以兼容TextField,理论上在TextField支持的操作,在TextSpanField同样支持。

我的主页:https://github.com/JiangJuHong