当前位置: 首页 > news >正文

【Flutter】 TextField限制长度时, 第三方手写输入法、ios原始拼音输入法输入被吞问题

问题描述

 TextField限制长度时, 当你的输入字符长度已经到了最大值-1时,使用第三方手写输入法或者ios原生拼音输入法输入liang(什么拼音都行,这里只是举例),输到i那么li都会消失。

原因分析

这是因为第三方手写输入法或者ios原生拼音输入法,虽然还没选中哪个汉子,但是输入的拼音字母已经显示在输入框了,那么这个字符串就会算作已经输入了,再计算TextField字符串长度的时候会加上未选中的拼音,跟最大长度作对比,字符数比最大值还要大的时候就会因为TextField的判定机制使未选中的字符消失。

解决方法

TextField除了使用maxLength设置最大长度外,还可以使用inputFormatters限制:

            TextField(controller: _controller,inputFormatters: [LengthLimitingTextInputFormatter(maxLength),],......

源码分析

LengthLimitingTextInputFormatter是flutter原生的类,代码如下:

class LengthLimitingTextInputFormatter extends TextInputFormatter {LengthLimitingTextInputFormatter(this.maxLength, {this.maxLengthEnforcement,}) : assert(maxLength == null || maxLength == -1 || maxLength > 0);final int? maxLength;  //传入的最大长度//确定应如何强制执行 maxLength 限制,默认为 MaxLengthEnforcement.enforcedfinal MaxLengthEnforcement? maxLengthEnforcement; //获取默认的maxLengthEnforcement,总共有三种,//有兴趣可以看文章最后或者看源码注释研究一下,这个问题的解决方法不需要这个方法static MaxLengthEnforcement getDefaultMaxLengthEnforcement([TargetPlatform? platform,]) {if (kIsWeb) {return MaxLengthEnforcement.truncateAfterCompositionEnds;} else {switch (platform ?? defaultTargetPlatform) {case TargetPlatform.android:case TargetPlatform.windows:return MaxLengthEnforcement.enforced;case TargetPlatform.iOS:case TargetPlatform.macOS:case TargetPlatform.linux:case TargetPlatform.fuchsia:return MaxLengthEnforcement.truncateAfterCompositionEnds;}}}//截断字符串@visibleForTestingstatic TextEditingValue truncate(TextEditingValue value, int maxLength) {final CharacterRange iterator = CharacterRange(value.text);if (value.text.characters.length > maxLength) {iterator.expandNext(maxLength);}final String truncated = iterator.current;return TextEditingValue(text: truncated,selection: value.selection.copyWith(baseOffset: math.min(value.selection.start, truncated.length),extentOffset: math.min(value.selection.end, truncated.length),),composing: !value.composing.isCollapsed && truncated.length > value.composing.start? TextRange(start: value.composing.start,end: math.min(value.composing.end, truncated.length),): TextRange.empty,);}//顾名思义,更新字符串,每次输入的值发生改变时都会调用。//根据字符串最大值以及maxLengthEnforcement判断返回的是什么。@overrideTextEditingValue formatEditUpdate(TextEditingValue oldValue,TextEditingValue newValue,) {final int? maxLength = this.maxLength;if (maxLength == null ||maxLength == -1 ||newValue.text.characters.length <= maxLength) {return newValue;}assert(maxLength > 0);switch (maxLengthEnforcement ?? getDefaultMaxLengthEnforcement()) {case MaxLengthEnforcement.none:return newValue;case MaxLengthEnforcement.enforced:if (oldValue.text.characters.length == maxLength && oldValue.selection.isCollapsed) {return oldValue;}return truncate(newValue, maxLength);case MaxLengthEnforcement.truncateAfterCompositionEnds:if (oldValue.text.characters.length == maxLength &&!oldValue.composing.isValid) {return oldValue;}if (newValue.composing.isValid) {return newValue;}return truncate(newValue, maxLength);}}
}

输入框显示的是什么是formatEditUpdate可以决定的,使用这次的更改主要是formatEditUpdate。

解决代码 

参考LengthLimitingTextInputFormatter写一个新的TextInputFormatter。

这里只改了formatEditUpdate,以及不需要判定maxLengthEnforcement,所以把相关代码也删了。

class MyLengthLimitingTextInputFormatter extends TextInputFormatter{final int? maxLength;MyLengthLimitingTextInputFormatter(this.maxLength) : assert(maxLength == null || maxLength == -1 || maxLength > 0);@visibleForTestingstatic TextEditingValue truncate(TextEditingValue value, int maxLength) {final CharacterRange iterator = CharacterRange(value.text);if (StringUtil.getTextLength(value.text) > maxLength) {iterator.expandNext(maxLength);}final String truncated = iterator.current;return TextEditingValue(text: truncated,selection: value.selection.copyWith(baseOffset: math.min(value.selection.start, truncated.length),extentOffset: math.min(value.selection.end, truncated.length),),composing: !value.composing.isCollapsed && truncated.length > value.composing.start? TextRange(start: value.composing.start,end: math.min(value.composing.end, truncated.length),): TextRange.empty,);}//oldValue就是显示在输入框上的旧值,newValue就是显示在输入框上的旧值加你新输入的字符串@overrideTextEditingValue formatEditUpdate(TextEditingValue oldValue,TextEditingValue newValue,) {final int? maxLength = this.maxLength;//加上你新输入的字符串都没大于限制的最大值就直接在输入框显示新字符串if (maxLength == null ||maxLength == -1 ||newValue.text.characters.length <= maxLength) {return newValue;}assert(maxLength > 0);//已经达到最大值且新输入的字符串不是正在输入的状态//(真正输入存活状态:拼音拼出的字还没选中(下面会有下划线)或者手写的字还没在输入法选中(下面会有下划线);//存活状态就是反过来,选中了或者输入英文的时候就是打出的每个字母都直接到输入框,下面也不会有下划线) ,直接返回旧的值if (oldValue.text.characters.length == maxLength && !newValue.composing.isValid) {return oldValue;}//已经达到最大值且新输入的字符串是正在输入的状态,显示旧值+你新输入的值=newValue,//就是这句解决了拼音会被吞的问题if (oldValue.text.characters.length == maxLength && newValue.composing.isValid){return newValue;}// Enforced to return a truncated value.return truncate(newValue, maxLength);}}

使用

将LengthLimitingTextInputFormatter换成MyLengthLimitingTextInputFormatter就行。

            TextField(controller: _controller,inputFormatters: [MyLengthLimitingTextInputFormatter(maxLength),],......

缺陷

但是这样的解决方法还有一个问题:只要你英文打的够快,然后快速选择还在输入法上没消失的待选择的字母,它就能吞了前面的字。

附上这个问题没用到的:maxLengthEnforcement的区别

 源码:

enum MaxLengthEnforcement {/// No enforcement applied to the editing value. It's possible to exceed the/// max length.none,/// Keep the length of the text input from exceeding the max length even when/// the text has an unfinished composing region.enforced,/// Users can still input text if the current value is composing even after/// reaching the max length limit. After composing ends, the value will be/// truncated.truncateAfterCompositionEnds,
}

none:限制长度后还是可以随便输入 ,设了等于没设;

enforced:当字符长度达到限制长度时,正在输入的字符停止输入后会强制消失,例如输入英文字符停手后就会从输入法消失

truncateAfterCompositionEnds:当字符长度达到限制长度时,但正在输入的字符强制不会消失,也就是输入法里面预选的字不会消失

另一个方法

网上找到的另一个我还没验证的方法:

https://juejin.cn/post/6844904096407765005

相关文章:

【Flutter】 TextField限制长度时, 第三方手写输入法、ios原始拼音输入法输入被吞问题

问题描述 TextField限制长度时&#xff0c; 当你的输入字符长度已经到了最大值-1时&#xff0c;使用第三方手写输入法或者ios原生拼音输入法输入liang&#xff08;什么拼音都行&#xff0c;这里只是举例&#xff09;&#xff0c;输到i那么li都会消失。 原因分析 这是因为第三…...

快递一键查询,只需快递单号,轻松掌握全程物流信息,让您的包裹追踪无忧!

在快节奏的现代生活中&#xff0c;快递已经成为我们生活中不可或缺的一部分。无论是网购的宝贝、亲朋好友寄来的礼物&#xff0c;还是工作中的紧急文件&#xff0c;快递都承载着我们的期待和需要。然而&#xff0c;面对众多的快递公司和复杂的查询流程&#xff0c;如何快速、准…...

【Java探索之旅】继承结构 继承和组合 protected final

文章目录 &#x1f4d1;前言一、继承1.1 继承关系的代码块1.2 protected关键字1.3 继承方式1.4 final关键字1.5 继承与组合 &#x1f324;️全篇总结 &#x1f4d1;前言 在面向对象编程中&#xff0c;继承是一种重要的概念&#xff0c;它允许我们创建一个新类&#xff0c;从现有…...

Ubuntu20.04-SLAM软件安装

目录 安装环境安装问题1.Ubuntu20.04在T440p上的安装问题1.1 安装后提示"x86/cpu:VMX(outside TXT) disabled by BIOS"1.2 ACPI Error:Needed type[Reference],found [Integer] 等错误1.3 ima: Error Communicating to TPM chip1.4 locate命令的安装 2.中文输入法-go…...

OSI七层网络参考模型

一、物理层 我们要发送出去的数据在计算机里只不过是无数的0和1&#xff0c;0或1就叫做比特&#xff0c;物理层就是把这些比特用不同的媒介传输出去&#xff0c;可以用电、光或者其他形式的电磁波来表示和传输信号&#xff0c;数据从网络接口出去以后&#xff0c;会经过不同的网…...

RAG与知识库搭建

Tip: 如果你在进行深度学习、自动驾驶、模型推理、微调或AI绘画出图等任务&#xff0c;并且需要GPU资源&#xff0c;可以考虑使用UCloud云计算旗下的Compshare的GPU算力云平台。他们提供高性价比的4090 GPU&#xff0c;按时收费每卡2.6元&#xff0c;月卡只需要1.7元每小时&…...

MySQL提权之UDF提权

1、前言 最近遇到udf提权&#xff0c;几经周折终于搞懂了。感觉挺有意思的&#xff0c;渗透思路一下子就被打开了。 2、什么是udf提权 udf 全称为user defined function&#xff0c;意思是用户自定义函数。用户可以对数据库所使用的函数进行一个扩展&#xff08;windows利用…...

【设计模式】结构型设计模式之 组合模式

介绍 这里的组合模式&#xff0c;与之前的设计模式中的"组合关系"完全是两码事&#xff0c;这里的组合模式主要用来处理结构为树形的数据。 组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许你将对象组合成树状结构来表示…...

我给KTV服务生讲解防抖,他竟然听懂了

端午节三天假期&#xff0c;的最后一天&#xff0c;我和朋友闲来无事&#xff0c;想着去唱会儿歌吧&#xff0c;好久不唱了&#xff0c;于是吃了午饭&#xff0c;石景山就近找了一家KTV&#xff0c;我们团好了卷就过去了。 装修还算不错&#xff0c;很快找到服务生&#xff0c…...

抽象java入门1.3.1

前言&#xff1a; 本期内容是为了更好补充关于方法&#xff08;函数&#xff09;的定义 开始&#xff1a; 函数&#xff08;function&#xff09;表示每个输入值对应唯一输出值的一种对应关系。 核心在于&#xff1a;输入值和输出值这两个元素 真的吗&#xff1f; 错&…...

使用Rufus工具制作Ubuntu To Go——很详细

一、准备工作 准备工具&#xff1a; 1、下载Rufus(主角)软件 2、准备一个U盘&#xff08;制作启动盘&#xff0c;32G足够&#xff09; 3、准备一个U盘或硬盘&#xff08;小白128G足够&#xff0c;装Ubuntu系统&#xff09; 4、下载Ubuntu系统镜像文件 1、下载软件Rufus 先来看…...

Android Jetpack Compose 实现一个电视剧选集界面

文章目录 需求概述效果展示实现思路代码实现总结 需求概述 我们经常能看到爱奇艺或者腾讯视频这类的视频APP在看电视剧的时候都会有一个选集的功能。如下图所示 这个功能其实很简单&#xff0c;就是绘制一些方块&#xff0c;在上面绘制上数字&#xff0c;还有标签啥的。当用户…...

C++多线程并发

文章目录 C多线程并发std::chronoC中的多线程&#xff1a;std::thread主线程等待子线程结束&#xff1a;join主线程分离子线程&#xff1a;detach异步&#xff1a;std::async异步的另一种用法&#xff1a;std::launch::deferredstd::async的底层实现&#xff1a;std::promisest…...

新火种AI|摊上事儿了!13名OpenAI与谷歌员工联合发声:AI失控可能导致人类灭绝...

作者&#xff1a;小岩 编辑&#xff1a;彩云 2024年&#xff0c;OpenAI的CEO Sam Altman就没有清闲过&#xff0c;他似乎一直走在解决麻烦的路上。最近&#xff0c;他的麻烦又来了。 当地时间6月4日&#xff0c;13位来自OpenAI和Google Deep Mind的现任及前任员工联合发布了…...

Web前端后端精通:深度解析与技能进阶

Web前端后端精通&#xff1a;深度解析与技能进阶 在数字时代的浪潮中&#xff0c;Web前端后端技术的精通成为了信息科技领域的核心竞争力。本文将从四个方面、五个方面、六个方面和七个方面深入探讨Web前端后端技术的精髓&#xff0c;带领读者领略这一领域的魅力与挑战。 一、…...

【C语言】09.函数递归

递归其实是⼀种解决问题的方法&#xff0c;在C语言中&#xff0c;递归就是函数自己调用自己。 一、递归的介绍 1.1递归的思想 把⼀个大型复杂问题层层转化为⼀个与原问题相似&#xff0c;但规模较小的子问题来求解&#xff1b;直到子问题不能再被拆分&#xff0c;递归就结束…...

php高级之框架源码、宏扩展原理与开发

在使用框架的时候我们经常会看到如下代码 类的方法不会显示地声明在代码里面&#xff0c;而是通过扩展的形式后续加进去&#xff0c;这么做的好处是可以降低代码的耦合度、保证源码的完整性、团队开发的时候可以分别写自己的服务去扩展类&#xff0c;减少代码冲突等等。我自己…...

(2024,示例记忆,模型记忆,遗忘,差分评估,概率评估)深度学习中的记忆:综述

Memorization in deep learning: A survey 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0 摘要 1 引言 0 摘要 深度神经网络&#xff08;DNNs&#xff09;驱动的深度学习&#xff…...

硬件产品经理

边端协调管理平台 主页一&#xff1a;模型管理1.1 边侧模型管理 二&#xff1a;配置管理2.1 终端软件配置管理 三&#xff1a;设备管理3.1 区域位置管理3.2 工控机管理&#xff08;其实就是围绕授权&#xff09;3.3 生产设备管理3.4 设备运行管理 四&#xff1a;数据服务4.1 实…...

AES加密、解密工具类

1、AES加密、解密工具类 这篇文章,主要记录一下AES加密、解密的工具类代码,在需要使用的时候,直接复制黏贴即可。 package com.gitcode.pms.common.util;import org.slf4j.Logger; import org.slf4j.LoggerFactory;import javax.crypto.Cipher; import javax.crypto.spec.…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...