flutter TextField@人或者#事件

2023-11-26  本文已影响0人  Pino

废话少说,先直接看效果图

艾特.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; // 下一次从上次发现的位置开始往后寻找
    }
  }

我这边使用正则来比配,感觉没有那么绕脑,第二种方式也可以,看个人使用
以下是文件夹结构


image.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('|');
  }

直接定义一个类就可以,其实原生也可以直接这样,省事,通俗易懂,只是懒得去修改原生的了

image.png
代码传送门 https://gitee.com/Pino_W/flutter_ait
上一篇 下一篇

猜你喜欢

热点阅读