flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能

flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能

最近有位朋友讨论的时候,提到了输入框的高亮展示。在flutter TextField中需要插入特殊样式的标签,比如:“请 @张三 回答一下”,这一串字符在TextField中输入,当输入@时 弹出好友列表选择,然后将 “@张三”高亮显示在TextField中。

https://blog.csdn.net/gloryFlow/article/details/132889374

效果图如下

在这里插入图片描述

一、TextEditingController中的buildTextSpan

在TextField中,我们找到TextEditingController的buildTextSpan方法。

buildTextSpan功能如下:根据当前编辑值生成[TextSpan],默认情况下,使组成范围内的文本显示为带下划线。继承可以重写此方法以自定义文本的外观。

我这里继承TextEditingController,重写buildTextSpan方法,

List<InlineSpan> textSpans = RichTextHelper.getRichText(value.text);if (composingRegionOutOfRange) {return TextSpan(style: style, children: textSpans);}

完整代码如下

import 'package:flutter/material.dart';
import 'package:flutter_lab/rich_text_helper.dart';class TextFieldController extends TextEditingController {/// Builds [TextSpan] from current editing value.////// By default makes text in composing range appear as underlined. Descendants/// can override this method to customize appearance of text.@overrideTextSpan buildTextSpan({required BuildContext context,TextStyle? style,required bool withComposing}) {assert(!value.composing.isValid ||!withComposing ||value.isComposingRangeValid);// If the composing range is out of range for the current text, ignore it to// preserve the tree integrity, otherwise in release mode a RangeError will// be thrown and this EditableText will be built with a broken subtree.final bool composingRegionOutOfRange =!value.isComposingRangeValid || !withComposing;print("--- composingRegionOutOfRange:${composingRegionOutOfRange},withComposing:${withComposing},value.isComposingRangeValid:${value.isComposingRangeValid}");List<InlineSpan> textSpans = RichTextHelper.getRichText(value.text);if (composingRegionOutOfRange) {return TextSpan(style: style, children: textSpans);}print("+++ composingRegionOutOfRange:${composingRegionOutOfRange}");final TextStyle composingStyle =style?.merge(const TextStyle(decoration: TextDecoration.underline)) ??const TextStyle(decoration: TextDecoration.underline);return TextSpan(style: style,children: <TextSpan>[TextSpan(text: value.composing.textBefore(value.text)),TextSpan(style: composingStyle,text: value.composing.textInside(value.text),),TextSpan(text: value.composing.textAfter(value.text)),],);}
}

二、设置@高亮

实现将 “@张三”高亮显示在TextField中,需要正则表达是,匹配到@功能正则表达式:String regexStr =
r"@[@]*[@ ]+[^@]* ";

使用RegExp

String regexStr =r"@[^@]*[^@ ]+[^@]* ";RegExp exp = RegExp('$regexStr');

具体代码如下

import 'package:flutter/material.dart';class RichTextHelper {//图文混排static getRichText(String text) {List<InlineSpan> textSpans = [];String regexStr =r"@[^@]*[^@ ]+[^@]* ";RegExp exp = RegExp('$regexStr');//正则表达式是否在字符串[input]中有匹配。if (exp.hasMatch(text)) {Iterable<RegExpMatch> matches = exp.allMatches(text);int index = 0;int count = 0;for (var matche in matches) {count++;String c = text.substring(matche.start, matche.end);//匹配到的东西,如表情在首位if (index == matche.start) {index = matche.end;}//匹配到的东西,如表情不在首位else if (index < matche.start) {String leftStr = text.substring(index, matche.start);index = matche.end;textSpans.add(TextSpan(text: spaceWord(leftStr),style: getDefaultTextStyle(),),);}//匹配到的网址if (RegExp(regexStr).hasMatch(c)) {textSpans.add(TextSpan(text: spaceWord(c),style:TextStyle(color: Colors.blueAccent, fontSize: 16),),);}//是否是最后一个表情,并且后面是否有字符串if (matches.length == count && text.length > index) {String rightStr = text.substring(index, text.length);textSpans.add(TextSpan(text: spaceWord(rightStr),style: getDefaultTextStyle(),),);}}} else {textSpans.add(TextSpan(text: spaceWord(text),style: getDefaultTextStyle(),),);}return textSpans;}static TextStyle getDefaultTextStyle() {return TextStyle(fontSize: 16,fontWeight: FontWeight.w400,fontStyle: FontStyle.normal,color: Colors.black87,decoration: TextDecoration.none,);}static String spaceWord(String text) {if (text.isEmpty) return text;String spaceWord = '';for (var element in text.runes) {spaceWord += String.fromCharCode(element);spaceWord += '\u200B';}return spaceWord;}
}

三、创建TextField

创建需要显示的TextField,设置输入框的onTap、onChanged、focusNode、TextEditingController等

代码如下

// 输入框
class InputTextField extends StatefulWidget {const InputTextField({Key? key,this.inputOnTap,this.inputOnChanged,this.inputOnSubmitted,this.inputOnEditingCompleted,this.autofocus = false,required this.textEditingController,}) : super(key: key);final inputOnTap;final inputOnChanged;final inputOnSubmitted;final inputOnEditingCompleted;final bool autofocus;final TextEditingController textEditingController;@overrideState<InputTextField> createState() => _InputTextFieldState();
}class _InputTextFieldState extends State<InputTextField> {FocusNode editFocusNode = FocusNode();@overridevoid initState() {// TODO: implement initStatesuper.initState();}//获取焦点void getFocusFunction(BuildContext context) {FocusScope.of(context).requestFocus(editFocusNode);}//失去焦点void unFocusFunction() {editFocusNode.unfocus();}@overridevoid dispose() {// TODO: implement disposeeditFocusNode.unfocus();editFocusNode.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Container(padding: EdgeInsets.only(left: 10.0,top: 5.0,bottom: 5.0,),constraints: BoxConstraints(minHeight: 40.0,maxHeight: 120.0,),child: TextField(onTap: () {widget.inputOnTap();},onChanged: (string) {widget.inputOnChanged(string);},onEditingComplete: () {widget.inputOnEditingCompleted();},onSubmitted: (string) {widget.inputOnSubmitted(string);},minLines: 1,maxLines: null,keyboardType: TextInputType.multiline,textAlignVertical: TextAlignVertical.center,autofocus: widget.autofocus,focusNode: editFocusNode,controller: widget.textEditingController,textInputAction: TextInputAction.send,decoration: InputDecoration(contentPadding: EdgeInsets.symmetric(vertical: 10, horizontal: 8.0),filled: true,isCollapsed: true,floatingLabelBehavior: FloatingLabelBehavior.never,hintText: "说点什么吧~",hintStyle: TextStyle(fontSize: 14,fontWeight: FontWeight.w400,fontStyle: FontStyle.normal,color: ColorUtil.hexColor(0xACACAC),decoration: TextDecoration.none,),enabledBorder: OutlineInputBorder(/*边角*/borderRadius: const BorderRadius.all(Radius.circular(5.0), //边角为30),borderSide: BorderSide(color: ColorUtil.hexColor(0xf7f7f7), //边框颜色为绿色width: 1, //边线宽度为1),),focusedBorder: OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(5.0), //边角为30),borderSide: BorderSide(color: ColorUtil.hexColor(0xECECEC), //边框颜色为绿色width: 1, //宽度为1),),),),);}
}

四、TextField赋text演示

最后我们可以在输入框TextField设置文本

TextFieldController textEditingController = TextFieldController();textEditingController.text = "你好@张三 欢迎,哈哈,haha";

完整代码如下

class TextFieldRich extends StatefulWidget {const TextFieldRich({super.key});@overrideState<TextFieldRich> createState() => _TextFieldRichState();
}class _TextFieldRichState extends State<TextFieldRich> {TextFieldController textEditingController = TextFieldController();@overridevoid initState() {// TODO: implement initStatesuper.initState();textEditingController.text = "你好@张三 欢迎,哈哈,haha";}@overridevoid dispose() {// TODO: implement disposesuper.dispose();}@overrideWidget build(BuildContext context) {Size scrSize = MediaQuery.of(context).size;return Scaffold(appBar: AppBar(// Here we take the value from the MyHomePage object that was created by// the App.build method, and use it to set our appbar title.title: Text('TextField测试页面'),),body: Container(width: scrSize.width,height: scrSize.height,color: Colors.greenAccent,alignment: Alignment.center,padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0),child: InputTextField(textEditingController: textEditingController),),);}
}

至此可以看到效果图中@张三 高亮显示了。

五、小结

flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能。该示例中,光标会有问题,暂时没做修改,后续抽空修改。

https://blog.csdn.net/gloryFlow/article/details/132889374

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/134951.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

群辉 Synology NAS Docker 安装 RustDesk-server 自建服务器只要一个容器

from https://blog.zhjh.top/archives/M8nBI5tjcxQe31DhiXqxy 简介 之前按照网上的教程&#xff0c;rustdesk-server 需要安装两个容器&#xff0c;最近想升级下版本&#xff0c;发现有一个新镜像 rustdesk-server-s6 可以只安装一个容器。 The S6-overlay acts as a supervi…

NSS [HNCTF 2022 WEEK2]ohmywordpress(CVE-2022-0760)

NSS [HNCTF 2022 WEEK2]ohmywordpress&#xff08;CVE-2022-0760&#xff09; 题目描述&#xff1a;flag在数据库里面。 开题&#xff1a; 顺着按钮一直点下去会发现出现一个按钮叫安装WordPress 安装完之后的界面&#xff0c;有一个搜索框。 F12看看network。 又出现了这个…

day22集合01

1.Collection集合 1.1数组和集合的区别【理解】 相同点 都是容器,可以存储多个数据 不同点 数组的长度是不可变的,集合的长度是可变的 数组可以存基本数据类型和引用数据类型 集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类 1.2集合类体系结构【理解】…

【Axure原型素材】扫一扫

今天和粉丝们免费分享扫一扫的原型素材&#xff0c;"扫一扫"是一项常见的移动应用功能&#xff0c;通常通过手机或平板电脑上的摄像头来扫描二维码或条形码以实现各种功能。下面是和大家分享扫一扫的常用素材~~~ 【原型效果】 【Axure原型素材】扫一扫 【原型预览】…

【环境配置】基于Docker配置Chisel-Bootcamp环境

文章目录 Chisel是什么Chisel-Bootcamp是什么基于Docker配置Chisel-Bootcamp官网下载Docker安装包Docker换源启动Bootcamp镜像常用docker命令 可能产生的问题 Chisel是什么 Chisel是Scala语言的一个库&#xff0c;可以由Scala语言通过import引入。 Chisel编程可以生成Verilog代…

IDEA创建完Maven工程后,右下角一直显示正在下载Maven插件

原因&#xff1a; 这是由于新建的Maven工程&#xff0c;IDEA会用它内置的默认的Maven版本&#xff0c;使用国外的网站下载Maven所需的插件&#xff0c;速度很慢 。 解决方式&#xff1a; 每次创建 Project 后都需要设置 Maven 家目录位置&#xff08;就是我们自己下载的Mav…

嵌入式:驱动开发 Day2

作业&#xff1a;字符设备驱动&#xff0c;完成三盏LED灯的控制 驱动代码&#xff1a; mychrdev.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h> #include &q…

Windows/Linux(命令、安装包和源码安装)平台各个版本QT详细安装教程

前言 本文章主要介绍了Windows/Linux平台下&#xff0c;QT4&#xff0c;QT5&#xff0c;QT6的安装步骤。为什么要把QT版本分开介绍呢&#xff0c;因为这三个版本&#xff0c;安装步骤都不一样。Windows平台&#xff0c;QT4的Qt Creator&#xff0c;QT库和编译器是分开的&#…

Android Studio 报错问题记录

工具地址 由于之前手贱不知道点了一个什么东西更新&#xff0c;导致一个code1报错&#xff0c;后来又一通瞎比操作直接吧Android Studio弄得打不开模拟器了&#xff0c;所以我后面就全部卸载重新安装了一下&#xff0c;并把之前遇到的问题做下记录&#xff0c;可能并不适用于每…

笔记1.5:计算机网络体系结构

从功能上描述计算机网络结构 分层结构 每层遵循某个网络协议完成本层功能 基本概念 实体&#xff1a;表示任何可发送或接收信息的硬件或软件进程。 协议是控制两个对等实体进行通信的规则的集合&#xff0c;协议是水平的。 任一层实体需要使用下层服务&#xff0c;遵循本层…

自定义实现简易版ArrayList

文章目录 1.了解什么是顺序表2.实现哪些功能3.初始化ArrayList4.实现功能接口遍历顺序表判断顺序表是否已满添加元素指定下标添加元素自定义下标不合法异常判断顺序表是否为空查找指定元素是否存在查找指定元素返回下标获取指定下标的元素顺序表为空异常修改指定下标元素的值删…

Stable DIffusion 炫酷应用 | AI嵌入艺术字+光影光效

目录 1 生成AI艺术字基本流程 1.1 生成黑白图 1.2 启用ControlNet 参数设置 1.3 选择大模型 写提示词 2 不同效果组合 2.1 更改提示词 2.2 更改ControlNet 2.2.1 更改模型或者预处理器 2.2.2 更改参数 3. 其他应用 3.1 AI光影字 本节需要用到ControlNet&#xff0c;可…

手摸手系列之前端Vue实现PDF预览及打印的终极解决方案

前言 近期我正在开发一个前后端分离项目&#xff0c;使用了Spring Boot 和 Vue2&#xff0c;借助了国内优秀的框架 jeecg&#xff0c;前端UI库则选择了 ant-design-vue。在项目中&#xff0c;需要实现文件上传功能&#xff0c;同时还要能够在线预览和下载图片和PDF文件&#x…

[golang 流媒体在线直播系统] 4.真实RTMP推流摄像头把摄像头拍摄的信息发送到腾讯云流媒体服务器实现直播

用RTMP推流摄像头把摄像头拍摄的信息发送到腾讯云流媒体服务器实现直播,该功能适用范围广,比如:幼儿园直播、农场视频直播, 一.准备工作 要实现上面的功能,需要准备如下设备: 推流摄像机&#xff08;监控&#xff09; 流媒体直播服务器(腾讯云流媒体服务器,自己搭建的流媒体服务…

MySQL 面试题——MySQL 基础

目录 1.什么是 MySQL&#xff1f;有什么优点&#xff1f;2.MySQL 中的 DDL 与 DML 是分别指什么&#xff1f;3.✨数据类型 varchar 与 char 有什么区别&#xff1f;4.数据类型 BLOB 与 TEXT 有什么区别&#xff1f;5.DATETIME 和 TIMESTAMP 的异同&#xff1f;6.✨MySQL 中 IN …

Json-Jackson和FastJson

狂神&#xff1a; 测试Jackson 纯Java解决日期格式化 设置ObjectMapper FastJson&#xff1a; 知乎&#xff1a;Jackson使用指南 1、常见配置 方式一&#xff1a;yml配置 spring.jackson.date-format指定日期格式&#xff0c;比如yyyy-MM-dd HH:mm:ss&#xff0c;或者具体的…

线程池(重点)

1.线程池的三大方法 package com.kuang.pool;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //Executors工具类 三大方法 //使用线程池&#xff0c;创建线程 public class Demo01 {public static void main(String[] args) { // …

Python + Jmeter 实现自动化性能压测

Step01: Python脚本开发 文件路径&#xff1a;D://wl//testproject//Fone-grpc//project1//test_client.py Python 脚本作用&#xff1a; 通过 grpc 调用底层 c 的接口&#xff0c;做数据库的数据插入与查询操作&#xff0c;然后将返回的结果进行拼接与输出。 2.代码里面将…

LeNet-5

目录 一、知识点 二、代码 三、查看卷积层的feature map 1. 查看每层信息 ​2. show_featureMap.py 背景&#xff1a;LeNet-5是一个经典的CNN&#xff0c;由Yann LeCun在1998年提出&#xff0c;旨在解决手写数字识别问题。 一、知识点 1. iter()next() iter()&#xff1a;…

阿里云无影云电脑介绍_云办公_使用_价格和优势说明

什么是阿里云无影云电脑&#xff1f;无影云电脑&#xff08;原云桌面&#xff09;是一种快速构建、高效管理桌面办公环境&#xff0c;无影云电脑可用于远程办公、多分支机构、安全OA、短期使用、专业制图等使用场景&#xff0c;阿里云百科分享无影云桌面的详细介绍、租用价格、…