Flutter驗(yàn)證碼輸入框的2種方法實(shí)現(xiàn)
本文向您展示了在 Flutter 中實(shí)現(xiàn)完美的驗(yàn)證碼輸入框幾種不同方法。
重點(diǎn)是什么?
真實(shí)世界的 完美的驗(yàn)證碼輸入框或 PIN 輸入 UI 通常滿足以下最低要求:
- 有4個(gè)或6個(gè)文本域,每個(gè)文本域只能接受1個(gè)字符(通常是一個(gè)數(shù)字)
- 輸入數(shù)字后自動(dòng)聚焦下一個(gè)字段
您經(jīng)常在需要電話號(hào)碼確認(rèn)、電子郵件或雙因素身份驗(yàn)證的應(yīng)用程序中看到此功能。
從頭開(kāi)始制作 OTP 字段
應(yīng)用預(yù)覽

此示例創(chuàng)建一個(gè)簡(jiǎn)單的 OTP 屏幕。首先,聚焦第一個(gè)輸入字段。當(dāng)您輸入一個(gè)數(shù)字時(shí),光標(biāo)將自動(dòng)移動(dòng)到下一個(gè)字段。當(dāng)按下提交按鈕時(shí),您輸入的 OTP 代碼將顯示在屏幕上。
以下是它的工作原理:
測(cè)試此應(yīng)用程序時(shí),您應(yīng)該使用模擬器的軟鍵盤(pán)而不是計(jì)算機(jī)的硬件鍵盤(pán)。
代碼
創(chuàng)建一個(gè)名為OtpInput的可重用小部件:
// Create an input widget that takes only one digit
class OtpInput extends StatelessWidget {
final TextEditingController controller;
final bool autoFocus;
const OtpInput(this.controller, this.autoFocus, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: 60,
width: 50,
child: TextField(
autofocus: autoFocus,
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
controller: controller,
maxLength: 1,
cursorColor: Theme.of(context).primaryColor,
decoration: const InputDecoration(
border: OutlineInputBorder(),
counterText: '',
hintStyle: TextStyle(color: Colors.black, fontSize: 20.0)),
onChanged: (value) {
if (value.length == 1) {
FocusScope.of(context).nextFocus();
}
},
),
);
}
}
main.dart 中的完整源代碼和解釋?zhuān)ㄎ覍?strong>OtpInput類(lèi)放在文件底部):
import 'dart:math' as math;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:async/async.dart';
import 'package:flutter/scheduler.dart';
import 'package:url_strategy/url_strategy.dart';
void main() {
setPathUrlStrategy();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
// Hide the debug banner
debugShowCheckedModeBanner: false,
title: '堅(jiān)果',
theme: ThemeData(
primarySwatch: Colors.indigo,
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
String _imageUrl =
'https://luckly007.oss-cn-beijing.aliyuncs.com/image/image-20211124085239175.png';
double _fontSize = 20;
String _title = "堅(jiān)果公眾號(hào)";
// 4 text editing controllers that associate with the 4 input fields
final TextEditingController _fieldOne = TextEditingController();
final TextEditingController _fieldTwo = TextEditingController();
final TextEditingController _fieldThree = TextEditingController();
final TextEditingController _fieldFour = TextEditingController();
// This is the entered code
// It will be displayed in a Text widget
String? _otp;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('請(qǐng)輸入驗(yàn)證碼'),
const SizedBox(
height: 30,
),
// Implement 4 input fields
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
OtpInput(_fieldOne, true),
OtpInput(_fieldTwo, false),
OtpInput(_fieldThree, false),
OtpInput(_fieldFour, false)
],
),
const SizedBox(
height: 30,
),
ElevatedButton(
onPressed: () {
setState(() {
_otp = _fieldOne.text +
_fieldTwo.text +
_fieldThree.text +
_fieldFour.text;
});
},
child: const Text('提交')),
const SizedBox(
height: 30,
),
// Display the entered OTP code
Text(
_otp ?? '驗(yàn)證碼',
style: const TextStyle(fontSize: 30),
)
],
),
);
}
}
// Create an input widget that takes only one digit
class OtpInput extends StatelessWidget {
final TextEditingController controller;
final bool autoFocus;
const OtpInput(this.controller, this.autoFocus, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: 60,
width: 50,
child: TextField(
autofocus: autoFocus,
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
controller: controller,
maxLength: 1,
cursorColor: Theme.of(context).primaryColor,
decoration: const InputDecoration(
border: OutlineInputBorder(),
counterText: '',
hintStyle: TextStyle(color: Colors.black, fontSize: 20.0)),
onChanged: (value) {
if (value.length == 1) {
FocusScope.of(context).nextFocus();
}
},
),
);
}
}
使用第三個(gè)包
為了僅用幾行代碼快速實(shí)現(xiàn)您的目標(biāo),您可以使用第三方插件。在我們的例子中一些好的是pin_code_fields,otp_text_field等。 下面的例子將使用pin_code_fileds,它提供了很多很棒的功能:

- 自動(dòng)將下一個(gè)字段集中在打字上,將上一個(gè)字段集中在委派上
- 可以設(shè)置為任意長(zhǎng)度
- 高度可定制
- 輸入文本的 3 種不同類(lèi)型的動(dòng)畫(huà)
- 動(dòng)畫(huà)活動(dòng)、非活動(dòng)、選定和禁用字段顏色切換
- 自動(dòng)對(duì)焦選項(xiàng)
- 從剪貼板粘貼 OTP 代碼
您還可以在終端窗口中看到您輸入的字符:

代碼
1.安裝插件:
flutter pub add pin_code_fields
2.最終代碼:
import 'dart:math' as math;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:async/async.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:url_strategy/url_strategy.dart';
void main() {
setPathUrlStrategy();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
// Hide the debug banner
debugShowCheckedModeBanner: false,
title: '堅(jiān)果',
theme: ThemeData(
primarySwatch: Colors.indigo,
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
String _imageUrl =
'https://luckly007.oss-cn-beijing.aliyuncs.com/image/image-20211124085239175.png';
double _fontSize = 20;
String _title = "堅(jiān)果公眾號(hào)";
// 4 text editing controllers that associate with the 4 input fields
TextEditingController textEditingController = TextEditingController();
String currentText = "";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
body: Padding(
padding: const EdgeInsets.all(30),
child: Center(
child: PinCodeTextField(
length: 6,
obscureText: false,
animationType: AnimationType.fade,
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(5),
fieldHeight: 50,
fieldWidth: 40,
activeFillColor: Colors.white,
),
animationDuration: const Duration(milliseconds: 300),
backgroundColor: Colors.blue.shade50,
enableActiveFill: true,
controller: textEditingController,
onCompleted: (v) {
debugPrint("Completed");
},
onChanged: (value) {
debugPrint(value);
setState(() {
currentText = value;
});
},
beforeTextPaste: (text) {
return true;
},
appContext: context,
),
),
),
);
}
}
結(jié)論
我們已經(jīng)介紹了 2 個(gè)在 Flutter 中創(chuàng)建現(xiàn)代優(yōu)雅的 完美的驗(yàn)證碼輸入框/PIN 輸入字段的示例。
到此這篇關(guān)于Flutter驗(yàn)證碼輸入框的2種方法實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Flutter驗(yàn)證碼輸入框內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring和IDEA不推薦使用@Autowired?注解原因解析
這篇文章主要為大家介紹了Spring和IDEA不推薦使用@Autowired?注解原因解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
java實(shí)現(xiàn)簡(jiǎn)單的爬蟲(chóng)之今日頭條
最近在學(xué)習(xí)搜索方面的東西,需要了解網(wǎng)絡(luò)爬蟲(chóng)方面的知識(shí),雖然有很多開(kāi)源的強(qiáng)大的爬蟲(chóng),但本著學(xué)習(xí)的態(tài)度,想到之前在做資訊站的時(shí)候需要用到爬蟲(chóng)來(lái)獲取一些文章,今天剛好有空就研究了一下.在網(wǎng)上看到了一個(gè)demo,使用的是Jsoup,我拿過(guò)來(lái)修改了一下,有需要的朋友可以參考2016-11-11
why在重寫(xiě)equals時(shí)還必須重寫(xiě)hashcode方法分享
首先我們先來(lái)看下String類(lèi)的源碼:可以發(fā)現(xiàn)String是重寫(xiě)了Object類(lèi)的equals方法的,并且也重寫(xiě)了hashcode方法2013-10-10
java調(diào)用ffmpeg實(shí)現(xiàn)視頻轉(zhuǎn)換的方法
這篇文章主要介紹了java調(diào)用ffmpeg實(shí)現(xiàn)視頻轉(zhuǎn)換的方法,較為詳細(xì)分析了java視頻格式轉(zhuǎn)換所需要的步驟及具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-06-06
解決idea2020.1找不到程序包和符號(hào)的問(wèn)題
這篇文章主要介紹了解決idea2020.1找不到程序包和符號(hào)的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
SpringBoot常用計(jì)量與bean屬性校驗(yàn)和進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則全面分析
這篇文章主要介紹了SpringBoot常用計(jì)量、bean屬性校驗(yàn)與進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-10-10
關(guān)于JSqlparser使用攻略(高效的SQL解析工具)
這篇文章主要介紹了關(guān)于JSqlparser使用攻略(高效的SQL解析工具),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
Spring中配置和讀取多個(gè)Properties文件的方式方法
本篇文章主要介紹了Spring中配置和讀取多個(gè)Properties文件的方式方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04
使用@SpringBootTest注解進(jìn)行單元測(cè)試
這篇文章主要介紹了使用@SpringBootTest注解進(jìn)行單元測(cè)試,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
SpringBoot?SpringSecurity?JWT實(shí)現(xiàn)系統(tǒng)安全策略詳解
Spring?Security是Spring的一個(gè)核心項(xiàng)目,它是一個(gè)功能強(qiáng)大且高度可定制的認(rèn)證和訪問(wèn)控制框架。它提供了認(rèn)證和授權(quán)功能以及抵御常見(jiàn)的攻擊,它已經(jīng)成為保護(hù)基于spring的應(yīng)用程序的事實(shí)標(biāo)準(zhǔn)2022-11-11

