flutter TextField@人或者#事件
2023-11-26 本文已影响0人
Pino
废话少说,先直接看效果图
![](https://img.haomeiwen.com/i14078494/de0ad088b435c60c.gif)
之前在做原生安卓时候 实现过类似的功能,地址https://www.jianshu.com/p/5398df1c8f2c?v=1701076000905
近段时间转flutter ,也需要实现类似的需求,百度一下,发现这方面的文章很少,有的demo跑起来完全不是我需要的效果。
折腾了一两天,还是自己手动撸吧
这里仅仅演示了 添加文字块,没有演示删除效果,原因就是模拟器 flutter无法监听到模拟器的按键事件,准确说,是不能及时响应按键事件,我一直按住删除键,删除完所有才会触发,不知道是啥问题,真机测试没有问题
如果你想跑demo,不建议使用模拟器测试
如果你想跑demo,不建议使用模拟器测试
如果你想跑demo,不建议使用模拟器测试
这个功能 整理思路很重要,这里我回头分析了安卓版实现的原理,很多功能 flutter都是没法做到和原生一致的,都是换一种思路来实现。
不过flutter实现起来代码量很少,只有三个文件,大部分都是在FTextEditingController中实现,维护比较方便
flutter和原生最大的不同就是设置高亮颜色的方式,
原生是
editable.setSpan(new ForegroundColorSpan(color), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
flutter则是通过TextEditingController的buildTextSpan方法来重新拼接
比如说 “我是@张三啊实打实”,我想让“@张三”高亮,那么需要怎么拼接的
第一种方式是 ,通过正则来比配 “@张三”,则分成三部分 :“我是”,“@张三”,“啊实打实”
也就是三个TextSpan拼接起来 [TextSpan(“我是”).TextSpan(“@张三”),TextSpan(“啊实打实”)]
第二种是indexOf(highlight, start)来寻找@张三的起始位置,因为@张三有可能是多个,这里使用死循环来寻找
void highlight(){
int start = 0, end;
int index;
String text = "我是@张三啊实打实";
String highlight = '@张三';
while ((index = text.indexOf(highlight, start)) > -1) {
end = index + highlight.length;
// [index, end ]就是@张三的起始位置
start = end; // 下一次从上次发现的位置开始往后寻找
}
}
我这边使用正则来比配,感觉没有那么绕脑,第二种方式也可以,看个人使用
以下是文件夹结构
![](https://img.haomeiwen.com/i14078494/9b42dbd20c517488.png)
选择@人 或者#事件,这里没有使用原生的多态来实现,感觉多态不容易看懂,选择艾特一般就两三个类型,多态感觉用在大型项目比较合适,
// 这里就是模拟页面跳转选择之后,插入文字块
void addAit(){
int id=10;
String name="张三";
// 第一个参数就是拼接成@张三 格式,建议后面加空格,原生安卓版不加会有问题,
// 原因看安卓版有说明https://www.jianshu.com/p/5398df1c8f2c?v=1701076000905
// 第二哥参数就是 提交给后端的格式,可以自己自定义
SpanEntity span=SpanEntity("@${name} ","{[@$name,$id]}",color: Colors.blue);
_controller.insertSpan(span);
}
void addEvent(){
int id=9999;
String name="alan";
SpanEntity span=SpanEntity("#${name} ","{[#$name,$id]}",color: Colors.orange);
_controller.insertSpan(span);
}
void add$Span(){
int id=555;
String name="公司";
SpanEntity span=SpanEntity("\$${name} ","{[\$$name,$id]}",color: Colors.orange);
_controller.insertSpan(span);
}
// 如果使用$作为特殊字符开头,在Controller还要做一层处理不然,比配不到
String get rulerText {
return spanList.map((e) => e.text.startsWith('\$') ? '\\${e.text}' : e.text).toSet().toList().join('|');
}
直接定义一个类就可以,其实原生也可以直接这样,省事,通俗易懂,只是懒得去修改原生的了
![](https://img.haomeiwen.com/i14078494/6c9ab586ad37dda4.png)
代码传送门 https://gitee.com/Pino_W/flutter_ait