【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.enforced
  final 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;
      }
    }
  }

 //截断字符串
  @visibleForTesting
  static 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判断返回的是什么。
  @override
  TextEditingValue 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);

  @visibleForTesting
  static 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就是显示在输入框上的旧值加你新输入的字符串
  @override
  TextEditingValue 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[论文笔记]AIOS: LLM Agent Operating System

引言 这是一篇有意思的论文AIOS: LLM Agent Operating System&#xff0c;把LLM智能体(代理)看成是操作系统。 基于大语言模型(LLMs)的智能代理的集成和部署过程中存在着许多挑战&#xff0c;其中问题包括代理请求在LLM上的次优调度和资源分配&#xff0c;代理和LLM之间在交互…

苹果将推出“Apple Intelligence”AI系统,专注于隐私和广泛应用|TodayAI

据彭博社报道,苹果公司将在下周的 WWDC 2024 开发者大会上揭晓其全新的 AI 系统——“Apple Intelligence”,该系统将适用于 iPhone、iPad 和 Mac 设备。这一新系统将结合苹果自身技术和 OpenAI 的工具,为用户提供一系列新的 AI 功能,同时重点关注隐私保护和广泛应用。 与…

如何在virtualbox上安装Linux系统(centerOS)

提示&#xff1a;共同学习 注意&#xff1a;一定要在BIOS中的虚拟化打开。 文章目录 第一步&#xff1a; 第一步&#xff1a; 启动 、显示开启 centos基础安装 ​ ​

MongoDB CRUD操作:地理位置查询

MongoDB CRUD操作&#xff1a;地理位置查询 文章目录 MongoDB CRUD操作&#xff1a;地理位置查询地理空间数据GeoJSON对象传统坐标对通过数组指定&#xff08;首选&#xff09;通过嵌入文档指定 地理空间索引2dsphere2d 地理空间查询地理空间查询运算符地理空间聚合阶段 地理空…

【Linux】The server quit without updating PID file的几种解决方案

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 &#x1f913; 同时欢迎大家关注其他专栏&#xff0c;我将分享Web前后端开发、人工智能、机器学习、深…

Qt之QGraphicsView —— 笔记3:矩形图元连接(附完整源码)

效果 完整源码 注意:在ui文件中拖入一个QGraphicsView类窗口控件,然后用MyGraphicsView提升该类。 main.cpp #include "widget.h" #include <QApplication>int main(

【Java毕业设计】基于JSP+SSM的物流管理系统

文章目录 目 录摘要ABSTRACT1 概述1.1 课题背景及意义1.2 国内外研究现状1.3 本课题主要工作 2 系统开发环境2.1 JSP技术2.2 JavaScript2.3 B/S结构2.4 HTML简介 3 系统分析3.1 可行性分析3.1.1 技术可行性3.1.2操作可行性3.1.3 经济可行性3.1.4 法律可行性 3.2系统流程设计3.2…

ES开发及面试手册

入门基础 简介 Elasticsearch是一个基于Lucene的搜索和分析引擎&#xff0c;它提供了一个分布式、多租户能力的全文搜索引擎&#xff0c;具有HTTP Web界面和无模式JSON文档。 使用场景 什么是全文检索 全文检索 是一种信息检索技术&#xff0c;它允许用户通过输入查询关键词来…

CorelDRAW2024发布更新啦!设计师们的得力助手

在数字化的今天&#xff0c;视觉设计已经成为我们生活中不可或缺的一部分。从手机界面到广告海报&#xff0c;从网页布局到包装设计&#xff0c;每一个细节都离不开设计师们的专业与创意。然而&#xff0c;面对日益增长的设计需求和不断提升的审美标准&#xff0c;许多设计师开…

Unity ShaderGraph 扭曲

需要注意的是&#xff1a; HDRP ShaderGraph中 你不能扭曲UI&#xff0c;所以假如你要扭曲视频&#xff0c;请把视频在材质上渲染 播放&#xff0c;这样就可以扭曲视频了喔&#xff0c; ShaderGraph扭曲

vue-el-steps 使用2[代码示例]

效果图 代码 element代码 <template> <div class"app-container"> <el-form :model"queryForm" size"small" :inline"true"> <el-form-item label"内容状态"> <el-button-group> <el-bu…

单列集合.java

单列集合 为了存储不同类型的多个对象&#xff0c;Java提供了一些特殊系列的类&#xff0c;这些类可以存储任意类型的对象&#xff0c;并且存储的长度可变&#xff0c;这些类统称为集合。可以简单的理解为一个长度可变&#xff0c;可以存储不同数据类型的动态数组。集合都位于j…

编写程序,提示用户输入以米/秒(m/s)为单位的速度v和以米/秒的平方(m/s)为单位的加速度 a,然后显示最短跑道长度。

(物理:求出跑道长度)假设一个飞机的加速度是a而起飞速度是v&#xff0c;那么可以使用下 面的公式计算出飞机起飞所需的最短跑道长度: 编写程序&#xff0c;提示用户输入以米/秒(m/s)为单位的速度v和以米/秒的平方(m/s)为单 位的加速度 a&#xff0c;然后显示最短跑道长度。下面…

【数据结构】平衡二叉树左旋右旋与红黑树

平衡二叉树左旋右旋与红黑树 平衡二叉树 定义 平衡二叉树是二叉搜索树的一种特殊形式。二叉搜索树&#xff08;Binary Search Tree&#xff0c;BST&#xff09;是一种具有以下性质的二叉树&#xff1a; 对于树中的每个节点&#xff0c;其左子树中的所有节点都小于该节点的值…

求助!什么软件可以人声分离?手机上可以进行人声分离操作吗?

在数字时代&#xff0c;音频处理变得越来越重要&#xff0c;而人声分离技术则是其中的一项关键技术。很多人可能都有过这样的疑问&#xff1a;什么软件可以实现人声分离&#xff1f;手机上能否进行人声分离操作&#xff1f;今天&#xff0c;我们就来为大家解答这些问题&#xf…

Windows 系统安装 VisualSVN Server

一.下载 VisualSVN Server VisualSVN-Server 是 SVN 版本控制中服务器端要使用的软件,就是我们提交代码存在安装这个软件的电脑上,它将很多配置和服务直接帮你完成,简单好用容易上手。VisualSVN Server有三个版本,社区版免费但限15个用户,另有一般和‘企业’两个收费版本…

利用ArcGIS对长江三角洲地区的gdp水平进行聚类

1、导入矢量图、数据 长三角地区矢量图 长三角地区矢量图对应数据 2、连接 3、设置属性将人均gdp数据导入 4、设置标注和图例 选择布局视图 5、聚类 2020年人均gdp地区聚类 6、2005~2020年各地区人均gdp可视化及聚类汇总 &#xff08;1&#xff09;2005~2020可视化 2005 …

C#操作MySQL从入门到精通(13)——对查询结果使用函数

前言 我们有时候需要对查询到的数据使用函数进行处理,比如去掉空格,比如截取一半长度等操作,下面我来详细介绍: 本文使用的测试数据如下: 1、使用文本处理函数 1.1 Left 返回具有指定长度的字符串的左边部分 下面的代码获取email这个列从左边第一个字符开始计算的一共…

大模型基础——从零实现一个Transformer(1)

一、Transformer模型架构图 主要模块&#xff1a; embedding层&#xff1a; Input/Output Embedding&#xff1a; 将每个标记(token)转换为对应的向量表示。 Positional Encoding&#xff1a;由于没有时序信息&#xff0c;需要额外加入位置编码。 N个 block堆叠: Multi-Head …

自然语言处理(NLP)—— 语言检测器

1. 文章概述 1.1 目的 在本篇文章中&#xff0c;我们将构建一个语言检测器&#xff0c;这是一个能够识别文本语言的简单分类器。这是一个能够识别文本是用哪种语言写的程序。想象一下&#xff0c;你给这个程序一段文字&#xff0c;它就能告诉你这是英语、法语还是其他语言。 …