当前位置: 首页 > 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的常用方法总使…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践

在电商行业蓬勃发展的当下&#xff0c;多平台运营已成为众多商家的必然选择。然而&#xff0c;不同电商平台在商品数据接口方面存在差异&#xff0c;导致商家在跨平台运营时面临诸多挑战&#xff0c;如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...

PydanticAI快速入门示例

参考链接&#xff1a;https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...

高效的后台管理系统——可进行二次开发

随着互联网技术的迅猛发展&#xff0c;企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心&#xff0c;成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统&#xff0c;它不仅支持跨平台应用&#xff0c;还能提供丰富…...

Java中HashMap底层原理深度解析:从数据结构到红黑树优化

一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一&#xff0c;是基于哈希表的Map接口非同步实现。它允许使用null键和null值&#xff08;但只能有一个null键&#xff09;&#xff0c;并且不保证映射顺序的恒久不变。与Hashtable相比&#xff0c;Hash…...

在Spring Boot中集成RabbitMQ的完整指南

前言 在现代微服务架构中&#xff0c;消息队列&#xff08;Message Queue&#xff09;是实现异步通信、解耦系统组件的重要工具。RabbitMQ 是一个流行的消息中间件&#xff0c;支持多种消息协议&#xff0c;具有高可靠性和可扩展性。 本博客将详细介绍如何在 Spring Boot 项目…...