开箱即用,初始化时就唤起键盘,并选中第一个
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;
@override
State<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 = '';
@override
void initState() {
super.initState();
_verificationController = TextEditingController();
_verificationFocusNode = FocusNode();
// 监听验证码输入变化
_verificationController.addListener(() {
setState(() {
_verificationCode = _verificationController.text;
});
if (_verificationCode.length == 6) {
_forgetPasswordPage();
}
});
}
//忘记密码
void _forgetPasswordPage() async {
// 验证成功后跳转页面
}
@override
void 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 '已发送验证码';
}
}
@override
Widget 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,
),
),
),
// 后续功能组件(如登录按钮)可继续添加
],
),
),
),
],
),
);
}
}