Flutter中如何实现两次输入PIN码的一致性校验?
PIN码设置与确认功能实现方案
需求说明
页面初始显示文本**“为尾号XXXX的卡片设置PIN码”,用户输入第4位PIN码后,自动切换为“重新输入PIN码确认”**。需对比两次输入的PIN码,若不一致则显示提示文本,全程使用同一个PinFieldAutoFill组件。
页面效果参考
设置PIN码页面

重新输入PIN码页面

现有代码
SetPinTestscreen 代码
class _SetPinTestscreenState extends State<SetPinTestscreen> { TextEditingController setPinController = TextEditingController(); @override void initState() { Provider.of<PinValidationProvider>(context, listen: false).isPinSet = false; super.initState(); } @override Widget build(BuildContext context) { return MainTemplate( isFloatingButtonVisible: true, floatingButtonAction: () {}, child: Padding( padding: const EdgeInsets.all(15.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Align( alignment: Alignment.centerLeft, child: Consumer<PinValidationProvider>( builder: (context, pinProvider, child) { return Text( pinProvider.isPinSet ? 'Re-enter your PIN code to Confirm' : 'Set PIN for your Card Ending With XXXX', style: TextStyle(fontWeight: FontWeight.w700, fontSize: 30), ); }, ), ), SizedBox(height: 20), Center( child: PinFieldAutoFill( decoration: UnderlineDecoration( textStyle: Theme.of(context).textTheme.subtitle1.copyWith( fontWeight: FontWeight.bold, fontSize: 15, ), gapSpace: 8, lineHeight: 1.2, colorBuilder: PinListenColorBuilder(Colors.black, Colors.grey.shade400), ), onCodeChanged: (value) { Provider.of<PinValidationProvider>(context, listen: false) .validatePin(value, setPinController); }, codeLength: 4, cursor: Cursor(color: Colors.black, enabled: true), controller: setPinController, keyboardType: TextInputType.number, ), ), SizedBox(height: 20), Consumer<PinValidationProvider>( builder: (context, provider, child) { final textColor = provider.isInvalidPin ? Colors.red : Colors.black; return provider.isPinSet ? SizedBox.shrink() : Text( 'Pin must be at least 4 digits. It must not be single digits like' ' 1111 or digits in numerical order such as 1234', style: TextStyle( color: textColor, ), ); }), ], ), ), ); } }
PinValidationProvider 类代码
class PinValidationProvider extends ChangeNotifier { bool _isInvalidPin = false; bool get isInvalidPin => _isInvalidPin; bool isPinSet = false; String pin = ''; String confirmedPin = ''; void validatePin(String pin,TextEditingController controller) { if (pin.length != 4) { _isInvalidPin = false; pin = pin ?? ''; } else { confirmedPin = pin ?? ''; controller.clear(); if (_isSimpleSequence(pin) || _isRepeatedDigit(pin)) { _isInvalidPin = true; } else { _isInvalidPin = false; if (!isPinSet) { isPinSet = true; } } } Future.microtask(() { notifyListeners(); }); } bool _isSimpleSequence(String pin) { for (int i = 0; i < pin.length - 1; i++) { int digit1 = int.parse(pin[i]); int digit2 = int.parse(pin[i + 1]); if (digit2 - digit1 == 1) { return true; } } return false; } bool _isRepeatedDigit(String pin) { for (int i = 0; i < pin.length - 1; i++) { if (pin[i] == pin[i + 1]) { return true; } } return false; } }
修改实现方案
1. 完善 PinValidationProvider 逻辑
新增PIN不一致状态标记,调整验证流程:
class PinValidationProvider extends ChangeNotifier { bool _isInvalidPin = false; bool _isPinMismatch = false; // 标记两次PIN是否不一致 bool get isInvalidPin => _isInvalidPin; bool get isPinMismatch => _isPinMismatch; bool isPinSet = false; String _firstPin = ''; // 存储第一次输入的合法PIN void validatePin(String pin, TextEditingController controller) { if (pin.length != 4) { _isInvalidPin = false; _isPinMismatch = false; return; } // 第一次输入PIN:验证格式合法性 if (!isPinSet) { if (_isSimpleSequence(pin) || _isRepeatedDigit(pin)) { _isInvalidPin = true; _isPinMismatch = false; } else { _isInvalidPin = false; _firstPin = pin; isPinSet = true; controller.clear(); } } // 第二次输入PIN:验证与第一次是否一致 else { if (pin != _firstPin) { _isPinMismatch = true; controller.clear(); } else { _isPinMismatch = false; // PIN一致,可添加提交到服务器等后续逻辑 } } notifyListeners(); } // 重置状态(用于重新设置PIN场景) void resetPinState() { isPinSet = false; _firstPin = ''; _isInvalidPin = false; _isPinMismatch = false; notifyListeners(); } bool _isSimpleSequence(String pin) { for (int i = 0; i < pin.length - 1; i++) { int digit1 = int.parse(pin[i]); int digit2 = int.parse(pin[i + 1]); if (digit2 - digit1 == 1) { return true; } } return false; } bool _isRepeatedDigit(String pin) { for (int i = 0; i < pin.length - 1; i++) { if (pin[i] == pin[i + 1]) { return true; } } return false; } }
2. 更新 UI 层显示逻辑
添加PIN不一致提示,调整原有提示的显示条件:
class _SetPinTestscreenState extends State<SetPinTestscreen> { TextEditingController setPinController = TextEditingController(); @override void initState() { Provider.of<PinValidationProvider>(context, listen: false).resetPinState(); super.initState(); } @override Widget build(BuildContext context) { return MainTemplate( isFloatingButtonVisible: true, floatingButtonAction: () {}, child: Padding( padding: const EdgeInsets.all(15.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Align( alignment: Alignment.centerLeft, child: Consumer<PinValidationProvider>( builder: (context, pinProvider, child) { return Text( pinProvider.isPinSet ? '重新输入PIN码确认' : '为尾号XXXX的卡片设置PIN码', style: TextStyle(fontWeight: FontWeight.w700, fontSize: 30), ); }, ), ), SizedBox(height: 20), Center( child: PinFieldAutoFill( decoration: UnderlineDecoration( textStyle: Theme.of(context).textTheme.subtitle1.copyWith( fontWeight: FontWeight.bold, fontSize: 15, ), gapSpace: 8, lineHeight: 1.2, colorBuilder: PinListenColorBuilder(Colors.black, Colors.grey.shade400), ), onCodeChanged: (value) { if (value != null) { Provider.of<PinValidationProvider>(context, listen: false) .validatePin(value, setPinController); } }, codeLength: 4, cursor: Cursor(color: Colors.black, enabled: true), controller: setPinController, keyboardType: TextInputType.number, ), ), SizedBox(height: 20), Consumer<PinValidationProvider>( builder: (context, provider, child) { if (provider.isPinSet) { // 第二次输入时显示PIN不一致提示 return provider.isPinMismatch ? Text( '两次输入的PIN码不一致,请重新输入', style: TextStyle(color: Colors.red), ) : SizedBox.shrink(); } else { // 第一次输入时显示格式要求提示 final textColor = provider.isInvalidPin ? Colors.red : Colors.black; return Text( 'PIN码必须为4位,不能是连续数字(如1234)或重复数字(如1111)', style: TextStyle(color: textColor), ); } }), ], ), ), ); } }
核心逻辑说明
- 第一次输入PIN:验证格式合法性(非连续/重复数字),合法则存储PIN并切换到确认状态,同时清空输入框。
- 第二次输入PIN:直接对比与第一次输入的PIN,不一致则显示红色提示并清空输入框;一致则完成验证流程。
- 通过
ChangeNotifier实时通知UI更新状态,确保页面文本和提示的动态切换。
内容的提问来源于stack exchange,提问作者Mansoor Malik
相关产品推荐
相关产品推荐

