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

Flutter 验证码输入框

前言:

验证码输入框很常见:处理不好 bug也会比较多 想实现方法很多,这里列举一种完美方式,完美兼容 软键盘粘贴方式

效果如下:

之前使用 uniapp 的方式实现过一次 两种方式(原理相同):

input 验证码 密码 输入框_input密码输入框-CSDN博客文章浏览阅读3.9k次,点赞3次,收藏6次。前言:uniapp 在做需求的时候,经常会遇到;验证码输入框 或者 密码输框 自定义样式输入框 或者 格式化显示 银行卡 手机号码等等:这里总结了两种 常用的实现方式;从这两种实现方式 其实也能延伸出其他的显示 方式;先看样式: 自己实现 光标闪烁动画第一种:可以识别 获得焦点 失去焦点第一种实现的思路: 实际上就是,下层的真实 input 负责响应系统的输入,上面一层负责显示 应为输入框在手机端会 出现长按 学着 复制等等 输入框自带属..._input密码输入框https://blog.csdn.net/nicepainkiller/article/details/124384995?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171723341916800226511048%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171723341916800226511048&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-124384995-null-null.nonecase&utm_term=input&spm=1018.2226.3001.4450

实现原理拆解:

输入框区域我们分割成两层:

  • 6个黄色的区域 仅仅做展示,中间的黑色是一个动画 模拟光标闪烁 或者 展示 输入的数字
  • 最上层盖一个 输入框控件 接收输入事件,设置透明度 0.00001,设置不支持长按 选取复制,仅仅支持数字

这样一来就很明了, 逻辑也很简单

 具体实现:

  • 要实现 软键盘的 填充事件,所以我们需要动态监听 输入事件
    
    @override
    void initState() {// TODO: implement initStatesuper.initState();// 自动弹出软键盘Future.delayed(Duration.zero, () {FocusScope.of(context).requestFocus(_focusNode);});// 监听粘贴事件_textEditingController.addListener(() {if (Clipboard.getData('text/plain') != null) {Clipboard.getData('text/plain').then((value) {if (value != null && value.text != null) {if (value.text!.isNotEmpty && value.text!.length == 6) {if (RegExp(AppRegular.numberAll).firstMatch(value.text!) !=null) {_textEditingController.text = value!.text!;//取完值 置为 nullClipboard.setData(const ClipboardData(text: ''));//设置输入框光标到末尾 防止某些情况下 光标跑到前面,键盘无法删除输入字符_textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: _textEditingController.text.length),);}}}});}setState(() {_arrayCode = List<String>.filled(widget.length, '');for (int i = 0; i < _textEditingController.value.text.length; i++) {_arrayCode[i] = _textEditingController.value.text.substring(i, i + 1);}});if (_textEditingController.value.text.length == 6) {//防止重复触发 回调事件if (!_triggerState) {_triggerState = true;AppScreen.showToast('输入完成:${_textEditingController.value.text}');widget.onComplete(_textEditingController.value.text);}} else {_triggerState = false;}});
    }
  • 输入框的设置,禁止长按

    child: TextField(enableInteractiveSelection: false, // 禁用长按复制功maxLength: widget.length,focusNode: _focusNode,maxLines: 1,controller: _textEditingController,style: AppTextStyle.textStyle_32_333333,inputFormatters: [InputFormatter(AppRegular.numberAll)],decoration: const InputDecoration(focusedBorder: OutlineInputBorder(borderSide:BorderSide(width: 0, color: Colors.transparent)),disabledBorder: OutlineInputBorder(borderSide:BorderSide(width: 0, color: Colors.transparent)),enabledBorder: OutlineInputBorder(borderSide:BorderSide(width: 0, color: Colors.transparent)),border: OutlineInputBorder(borderSide:BorderSide(width: 0, color: Colors.transparent)),counterText: '', //取消文字计数器),
    )
  • 页面动画的展示,FadeTransition 为了性能优化到我们动画缩小到最小范围

    class InputFocusWidget extends StatefulWidget {const InputFocusWidget({Key? key}) : super(key: key);@overrideState<InputFocusWidget> createState() => _InputFocusWidgetState();
    }class _InputFocusWidgetState extends State<InputFocusWidget>with TickerProviderStateMixin {late AnimationController controller;late Animation<double> animation;@overridevoid initState() {// TODO: implement initStatesuper.initState();controller = AnimationController(duration: const Duration(milliseconds: 600), vsync: this);animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);controller.repeat(min: 0, max: 1, reverse: true);}@overridevoid dispose() {controller.dispose();// TODO: implement disposesuper.dispose();}@overrideWidget build(BuildContext context) {return FadeTransition(opacity: animation,child: Container(color: Colors.green,width: double.infinity,height: double.infinity,),);}
    }

完整代码:

 因为里面使用到我自己封装的一些工具,用的时候需要你转成自己的

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:game/utils/app_screen.dart';
import 'package:game/wrap/extension/extension.dart';
import 'package:game/wrap/overlay/app_overlay.dart';import '../const/app_regular.dart';
import '../const/app_textStyle.dart';
import 'input_formatter.dart';class InputWithCode extends StatefulWidget {final int length;final ValueChanged<String> onComplete;const InputWithCode({required this.length, required this.onComplete, Key? key}): super(key: key);@overrideState<InputWithCode> createState() => _InputWithCodeState();
}class _InputWithCodeState extends State<InputWithCode> {final TextEditingController _textEditingController = TextEditingController();bool _triggerState = false;late List<String> _arrayCode = List<String>.filled(widget.length, '');final FocusNode _focusNode = FocusNode();@overridevoid initState() {// TODO: implement initStatesuper.initState();// 自动弹出软键盘Future.delayed(Duration.zero, () {FocusScope.of(context).requestFocus(_focusNode);});// 监听粘贴事件_textEditingController.addListener(() {if (Clipboard.getData('text/plain') != null) {Clipboard.getData('text/plain').then((value) {if (value != null && value.text != null) {if (value.text!.isNotEmpty && value.text!.length == 6) {if (RegExp(AppRegular.numberAll).firstMatch(value.text!) !=null) {_textEditingController.text = value!.text!;Clipboard.setData(const ClipboardData(text: ''));_textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: _textEditingController.text.length),);}}}});}setState(() {_arrayCode = List<String>.filled(widget.length, '');for (int i = 0; i < _textEditingController.value.text.length; i++) {_arrayCode[i] = _textEditingController.value.text.substring(i, i + 1);}});if (_textEditingController.value.text.length == 6) {if (!_triggerState) {_triggerState = true;AppScreen.showToast('输入完成:${_textEditingController.value.text}');widget.onComplete(_textEditingController.value.text);}} else {_triggerState = false;}});}@overrideWidget build(BuildContext context) {return Container(width: double.infinity,height: double.infinity,child: Stack(children: [Center(child: Row(children: _arrayCode.asMap().map((index, value) => MapEntry(index,Container(width: 80.cale,height: 80.cale,margin: EdgeInsets.symmetric(horizontal: 10.cale),decoration: BoxDecoration(border: Border(bottom: BorderSide(width: 3.cale,color: value != ''? Colors.amberAccent: Colors.amberAccent.withOpacity(0.5),),),),child: index != _textEditingController.value.text.length? Center(child: Text(value,style: AppTextStyle.textStyle_40_1A1A1A_Bold,),): Center(child: SizedBox(width: 3.cale,height: 40.cale,child: const InputFocusWidget(),),),),),).values.toList(),),),Opacity(opacity: 0.0001,child: SizedBox(height: double.infinity,width: double.infinity,child: TextField(enableInteractiveSelection: false, // 禁用长按复制功maxLength: widget.length,focusNode: _focusNode,maxLines: 1,controller: _textEditingController,style: AppTextStyle.textStyle_32_333333,inputFormatters: [InputFormatter(AppRegular.numberAll)],decoration: const InputDecoration(focusedBorder: OutlineInputBorder(borderSide:BorderSide(width: 0, color: Colors.transparent)),disabledBorder: OutlineInputBorder(borderSide:BorderSide(width: 0, color: Colors.transparent)),enabledBorder: OutlineInputBorder(borderSide:BorderSide(width: 0, color: Colors.transparent)),border: OutlineInputBorder(borderSide:BorderSide(width: 0, color: Colors.transparent)),counterText: '', //取消文字计数器),),),),],),);}
}class InputFocusWidget extends StatefulWidget {const InputFocusWidget({Key? key}) : super(key: key);@overrideState<InputFocusWidget> createState() => _InputFocusWidgetState();
}class _InputFocusWidgetState extends State<InputFocusWidget>with TickerProviderStateMixin {late AnimationController controller;late Animation<double> animation;@overridevoid initState() {// TODO: implement initStatesuper.initState();controller = AnimationController(duration: const Duration(milliseconds: 600), vsync: this);animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);controller.repeat(min: 0, max: 1, reverse: true);}@overridevoid dispose() {controller.dispose();// TODO: implement disposesuper.dispose();}@overrideWidget build(BuildContext context) {return FadeTransition(opacity: animation,child: Container(color: Colors.green,width: double.infinity,height: double.infinity,),);}
}
使用:
  •  控件名称:InputWithCode
  •  length:验证码长度
  • onComplete: 输入完成回调
Container(child: InputWithCode(length: 6,onComplete: (code) => {print('InputWithCode:$code'),},),width: double.infinity,height: 200.cale,
),

相关文章:

Flutter 验证码输入框

前言&#xff1a; 验证码输入框很常见&#xff1a;处理不好 bug也会比较多 想实现方法很多&#xff0c;这里列举一种完美方式&#xff0c;完美兼容 软键盘粘贴方式 效果如下&#xff1a; 之前使用 uniapp 的方式实现过一次 两种方式&#xff08;原理相同&#xff09;&#xff1…...

如何从0到设计一个CRM系统

什么是CRM 设计开始之前&#xff0c;先来了解一下什么是CRM。CRM&#xff08;Customer Relationship Management&#xff09;是指通过建立和维护与客户的良好关系&#xff0c;达到满足客户需求、提高客户满意度、增加业务收入的一种管理方法和策略。CRM涉及到跟踪和管理客户的所…...

Numba 的 CUDA 示例 (2/4):穿针引线

本教程为 Numba CUDA 示例 第 2 部分。 按照本系列从头开始使用 Python 学习 CUDA 编程 介绍 在本系列的第一部分中&#xff0c;我们讨论了如何使用 GPU 运行高度并行算法。高度并行任务是指任务完全相互独立的任务&#xff0c;例如对两个数组求和或应用任何元素函数。 在本教…...

项目的各个阶段如何编写标准的Git commit消息

标准提交消息格式 一个标准的提交消息应包括三部分&#xff1a;标题&#xff08;summary&#xff09;、正文&#xff08;description&#xff09;和脚注&#xff08;footer&#xff09;。 1. 标题&#xff08;Summary&#xff09; 简洁明了&#xff0c;不超过50个字符。使用…...

Python课设-学生信息管理系统

一、效果展示图 二、前端代码 1、HTML代码 <1>index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">…...

openssl 常用命令demo

RSA Private Key的结构&#xff08;ASN.1&#xff09; RSAPrivateKey :: SEQUENCE { version Version, modulus INTEGER, -- n publicExponent INTEGER, -- e privateExponent INTEGER, -- d prime1 INTEGER, -- …...

【Linux】Linux基本指令2

目录 1.man指令&#xff08;重要&#xff09;&#xff1a; 2.echo指令 3.cp指令&#xff08;重要&#xff09;&#xff1a; 4.mv指令 5.cat指令/echo指令重定向 6.more指令 7.less指令&#xff08;重要&#xff09; 8.head指令 9.tail指令 我们接着上一篇&#xff1a;h…...

springboot+vue+mybatis博物馆售票系统+PPT+论文+讲解+售后

如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统博物馆售票系统信息管理难度大&#xff0c;容错率低&#xff0c;…...

java—MyBatis框架

简介 什么是 MyBatis&#xff1f; MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&…...

如何使用Spring Cache优化后端接口?

Spring Cache是Spring框架提供的一种缓存抽象,它可以很方便地集成到应用程序中,用于提高接口的性能和响应速度。使用Spring Cache可以避免重复执行耗时的方法,并且还可以提供一个统一的缓存管理机制,简化缓存的配置和管理。 本文将详细介绍如何使用Spring Cache来优化接口,…...

大话C语言:第21篇 数组

1 数组概述 数组是若干个相同类型的变量在内存中有序存储的集合。 数组是 C 语言中的一种数据结构&#xff0c;用于存储一组具有相同数据类型的数据。 数组在内存中会开辟一块连续的空间 数组中的每个元素可以通过一个索引&#xff08;下标&#xff09;来访问&#xff0c;索…...

transfomer中attention为什么要除以根号d_k

简介 得到矩阵 Q, K, V之后就可以计算出 Self-Attention 的输出了&#xff0c;计算的公式如下: A t t e n t i o n ( Q , K , V ) S o f t m a x ( Q K T d k ) V Attention(Q,K,V)Softmax(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)Softmax(dk​ ​QKT​)V 好处 除以维…...

iperf3带宽压测工具使用

iperf3带宽压测工具使用 安装下载地址&#xff1a;[下载入口](https://iperf.fr/iperf-download.php)测试结果&#xff1a;时长测试&#xff08;压测使用&#xff09;:并行测试反向测试UDP 带宽测试 iPerf3 是用于主动测试 IP 网络上最大可用带宽的工具 安装 下载地址&#x…...

[数据集][目标检测]焊接处缺陷检测数据集VOC+YOLO格式3400张8类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;3400 标注数量(xml文件个数)&#xff1a;3400 标注数量(txt文件个数)&#xff1a;3400 标注…...

2024华为OD机试真题-剩余银饰的重量-C++(C卷D卷)

题目描述 有 N 块二手市场收集的银饰,每块银饰的重量都是正整数,收集到的银饰会被熔化用于打造新的饰品。 每一回合,从中选出三块 最重的 银饰,然后一起熔掉。假设银饰的重量分别为 x 、y 和 z, 且 x <= y <= z。那么熔掉的可能结果如下: 如果x == y == z,那么三…...

糖果促销【百度之星】/思维

糖果促销 思维 大佬的解法&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; int main() {ll t;cin>>t;for(int i0;i<t;i){ll p,k;cin>>p>>k;if(k0) cout<<0<<endl;else{k-(k-1)/p;cout<<k<…...

【python学习】安装Anaconda后,如何进行环境管理(命令行操作及图形化操作Anaconda Navigator)及包管理

命令行的方式 首先&#xff0c;打开 Anaconda Powershell Prompt 环境查看 使用以下命令查看当前所有环境&#xff1a; conda env list目前只有一个 base环境&#xff0c;就是安装 anaconda的时候选择的。 光标在闪烁&#xff0c;目前已经进入 base 环境模式&#xff1a; …...

HTML大雪纷飞

目录 写在前面 HTML简介 完整代码 代码分析 运行结果 系列文章 写在后面 写在前面 小编又又又出现啦&#xff01;这次小编给大家带来大雪纷飞HTML版&#xff0c;不需要任何的环境&#xff0c;只要有一个浏览器&#xff0c;就可以随时随地下一场大雪哦&#xff01; HTM…...

问界新M7 Ultra仅售28.98万元起,上市即交付

5月31日&#xff0c;问界新M7 Ultra正式上市。发布会上&#xff0c;鸿蒙智行旗下多款产品交出最新答卷——问界新M5上市1个月大定突破2万台&#xff1b;智界S7位列30万纯电轿车4月交付量NO.3&#xff1b;问界M9上市5个月大定突破9万台。其中&#xff0c;作为中国高端豪华SUV市场…...

【Java数据结构】详解LinkedList与链表(四)

&#x1f512;文章目录&#xff1a; 1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; 2.什么是LinkedList 3.LinkedList的使用 3.1LinkedList的构造方法 3.2LinkedList的其他常用方法介绍 addAll方法 subList方法 LinkedList的常用方法总使…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

自然语言处理——文本分类

文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益&#xff08;IG&#xff09; 分类器设计贝叶斯理论&#xff1a;线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别&#xff0c; 有单标签多类别文本分类和多…...