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

Flutter 实现6个验收码输入框

开箱即用,初始化时就唤起键盘,并选中第一个

import 'package:flutter/material.dart';import 'dart:async'; // 引入 Timer 类class VerificationCode extends StatefulWidget {final String phoneNumber;const VerificationCode({super.key, required this.phoneNumber});static const double horizontalPadding = 28.0;@overrideState<VerificationCode> createState() => _VerificationCode();
}class _VerificationCode extends State<VerificationCode> {// ... 你已有的变量Timer? _timer;int _start = 0; // 倒计时秒数(比如 60)bool _isCounting = false;// 倒计时逻辑void _startCountdown() {setState(() {_start = 60; // 60s 倒计时_isCounting = true;});_timer = Timer.periodic(const Duration(seconds: 1), (timer) {if (_start == 1) {timer.cancel();setState(() {_isCounting = false;});} else {setState(() {_start--;});}});}late TextEditingController _verificationController; // 验证码输入控制器late FocusNode _verificationFocusNode;String _verificationCode = '';@overridevoid initState() {super.initState();_verificationController = TextEditingController();_verificationFocusNode = FocusNode();// 监听验证码输入变化_verificationController.addListener(() {setState(() {_verificationCode = _verificationController.text;});if (_verificationCode.length == 6) {_forgetPasswordPage();}});}//忘记密码void _forgetPasswordPage() async {// 验证成功后跳转页面}@overridevoid dispose() {_timer?.cancel();_verificationController.dispose();_verificationFocusNode.dispose();super.dispose();}void _handleLogin() {// TODO: 实现登录逻辑}String _getPhoneNumberLastFourDigits() {try {if (widget.phoneNumber.isEmpty) return '已发送验证码';if (!RegExp(r'^1[3-9]\d{9}$').hasMatch(widget.phoneNumber)) {return '已发送验证码';}final length = widget.phoneNumber.length;if (length >= 4) {return '已发送验证码至尾号${widget.phoneNumber.substring(length - 4)}';} else {return '已发送验证码';}} catch (_) {return '已发送验证码';}}@overrideWidget build(BuildContext context) {return Scaffold(resizeToAvoidBottomInset: true,body: Stack(children: [SingleChildScrollView(child: Container(height: MediaQuery.of(context).size.height,decoration: const BoxDecoration(color: Colors.white,image: DecorationImage(image: AssetImage('assets/pageBG/backgroundLogin.png'),fit: BoxFit.cover,),),child: Column(mainAxisAlignment: MainAxisAlignment.start,children: [const SizedBox(height: 56),Padding(padding: const EdgeInsets.only(left: 15),child: SizedBox(width: double.infinity,child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [GestureDetector(onTap: () {Navigator.pop(context);},child: Image.asset('assets/images/return.png',width: 20,height: 20,),),],),),),const SizedBox(height: 35),Container(margin: const EdgeInsets.symmetric(horizontal: VerificationCode.horizontalPadding,),alignment: Alignment.centerLeft,child: const Text('请输入验证码',style: TextStyle(color: Color.fromRGBO(51, 51, 51, 1),fontSize: 26,fontWeight: FontWeight.w500,),),),const SizedBox(height: 6),Container(width: double.infinity,margin: const EdgeInsets.symmetric(horizontal: VerificationCode.horizontalPadding,),child: Text(_getPhoneNumberLastFourDigits(),style: const TextStyle(color: Color.fromRGBO(102, 102, 102, 1),fontSize: 14,),),),const SizedBox(height: 42),// 验证码输入框GestureDetector(// 点击验证码输入框,使键盘弹出onTap: () {FocusScope.of(context,).requestFocus(_verificationFocusNode);},child: Container(width: double.infinity,height: 48,margin: const EdgeInsets.symmetric(horizontal: VerificationCode.horizontalPadding,),child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,children: List.generate(6, (index) {final isCurrentPosition =_verificationCode.length == index;final isFilled = _verificationCode.length > index;return Container(width: 45,height: 48,decoration: BoxDecoration(color: Colors.white,borderRadius: BorderRadius.circular(8),border: Border.all(color:isCurrentPosition? const Color(0xFF4D7CFE) // 当前输入位置:高亮蓝色: const Color.fromRGBO(227,227,227,1,), // 默认灰色边框width: 1.5,),),alignment: Alignment.center,child: Text(isFilled ? _verificationCode[index] : '',style: const TextStyle(fontSize: 20,fontWeight: FontWeight.w500,color: Color(0xFF333333),),),);}),),),),// 隐藏输入框Offstage(offstage: true,child: TextField(controller: _verificationController,focusNode: _verificationFocusNode,keyboardType: TextInputType.number,maxLength: 6,autofocus: true,decoration: const InputDecoration(counterText: '', // 隐藏 maxLength 计数器border: InputBorder.none,),),),// 忘记密码Container(width: double.infinity,padding: EdgeInsets.only(right: _isCounting ? 20 : 28,top: 10,),child: GestureDetector(onTap:_isCounting? null: () {// 调用你发送验证码的接口_startCountdown();},child: Text(_isCounting ? '重新获取(${_start}s)' : '重新获取',style: TextStyle(color:_isCounting? Colors.grey: const Color(0xFF4D7CFE), // 蓝色fontSize: 14,),textAlign: TextAlign.right,),),),// 后续功能组件(如登录按钮)可继续添加],),),),],),);}
}

相关文章:

  • 实现单例模式的6种方法(Python)
  • 防爆手机VS普通手机,区别在哪里?
  • 获取oracle的HQL日志,采取参数日志,拼装SQL语句
  • Oracle初识
  • Java大师成长计划之第32天:使用Kubernetes进行Java应用编排与管理
  • C++学习-入门到精通【9】面向对象编程:继承
  • 低空经济数据湖架构设计方案
  • 贝壳后端golang面经
  • 浅浅学:XCP协议原理及应用
  • ctf.show pwn入门 堆利用-前置基础 pwn142
  • STM32 Keil工程搭建 (手动搭建)流程 2025年5月27日07:42:09
  • Excel常用公式全解析(1):从基础计算到高级应用
  • STM32之FreeRTOS移植(重点)
  • 6.4.5_关键路径
  • 尚硅谷redis7 49-51 redis管道之理论简介
  • C++学习提问
  • day05-常用API(二):Lambda、方法引用详解
  • 洛谷 P3372 【模板】线段树 1
  • [学习]C语言指针函数与函数指针详解(代码示例)
  • 001 flutter学习的注意事项及前期准备
  • 重庆市工程建设招标投标交易信息网/武汉seo网站优化排名
  • 做网站有er图/百度号码认证平台个人号码申诉
  • wordpress 短网址/网站优化设计的基础是网站基本要素及每个细节的优化
  • 建设俄语网站/百度竞价排名查询
  • 可以做公务员题目的网站/北京疫情消息1小时前
  • 佛山新网站建设流程/软文推广产品