0


Flutter 完美的验证码输入框(2 种方法)

Flutter 完美的验证码输入框(2 种方法)

本文向您展示了在 Flutter 中实现完美的验证码输入框几种不同方法。

重点是什么?

真实世界的 完美的验证码输入框或 PIN 输入 UI 通常满足以下最低要求:

  • 有4个或6个文本域,每个文本域只能接受1个字符(通常是一个数字)
  • 输入数字后自动聚焦下一个字段

您经常在需要电话号码确认、电子邮件或双因素身份验证的应用程序中看到此功能。

从头开始制作 OTP 字段

应用预览

image-20211220134159049

此示例创建一个简单的 OTP 屏幕。首先,聚焦第一个输入字段。当您输入一个数字时,光标将自动移动到下一个字段。当按下提交按钮时,您输入的 OTP 代码将显示在屏幕上。

以下是它的工作原理:

测试此应用程序时,您应该使用模拟器的软键盘而不是计算机的硬件键盘。

代码

创建一个名为OtpInput的可重用小部件:

  1. // Create an input widget that takes only one digit
  2. class OtpInput extends StatelessWidget {
  3. final TextEditingController controller;
  4. final bool autoFocus;
  5. const OtpInput(this.controller, this.autoFocus, {Key? key}) : super(key: key);
  6. @override
  7. Widget build(BuildContext context) {
  8. return SizedBox(
  9. height: 60,
  10. width: 50,
  11. child: TextField(
  12. autofocus: autoFocus,
  13. textAlign: TextAlign.center,
  14. keyboardType: TextInputType.number,
  15. controller: controller,
  16. maxLength: 1,
  17. cursorColor: Theme.of(context).primaryColor,
  18. decoration: const InputDecoration(
  19. border: OutlineInputBorder(),
  20. counterText: '',
  21. hintStyle: TextStyle(color: Colors.black, fontSize: 20.0)),
  22. onChanged: (value) {
  23. if (value.length == 1) {
  24. FocusScope.of(context).nextFocus();
  25. }
  26. },
  27. ),
  28. );
  29. }
  30. }

main.dart 中的完整源代码和解释(我将OtpInput类放在文件底部):

  1. import 'dart:math' as math;
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:async/async.dart';
  5. import 'package:flutter/scheduler.dart';
  6. import 'package:url_strategy/url_strategy.dart';
  7. void main() {
  8. setPathUrlStrategy();
  9. runApp(MyApp());
  10. }
  11. class MyApp extends StatelessWidget {
  12. const MyApp({Key? key}) : super(key: key);
  13. @override
  14. Widget build(BuildContext context) {
  15. return MaterialApp(
  16. // Hide the debug banner
  17. debugShowCheckedModeBanner: false,
  18. title: '坚果',
  19. theme: ThemeData(
  20. primarySwatch: Colors.indigo,
  21. ),
  22. home: const HomeScreen(),
  23. );
  24. }
  25. }
  26. class HomeScreen extends StatefulWidget {
  27. const HomeScreen({Key? key}) : super(key: key);
  28. @override
  29. State<HomeScreen> createState() => _HomeScreenState();
  30. }
  31. class _HomeScreenState extends State<HomeScreen> {
  32. String _imageUrl =
  33. 'https://luckly007.oss-cn-beijing.aliyuncs.com/image/image-20211124085239175.png';
  34. double _fontSize = 20;
  35. String _title = "坚果公众号";
  36. // 4 text editing controllers that associate with the 4 input fields
  37. final TextEditingController _fieldOne = TextEditingController();
  38. final TextEditingController _fieldTwo = TextEditingController();
  39. final TextEditingController _fieldThree = TextEditingController();
  40. final TextEditingController _fieldFour = TextEditingController();
  41. // This is the entered code
  42. // It will be displayed in a Text widget
  43. String? _otp;
  44. @override
  45. Widget build(BuildContext context) {
  46. return Scaffold(
  47. appBar: AppBar(
  48. title: Text(_title),
  49. ),
  50. body: Column(
  51. mainAxisAlignment: MainAxisAlignment.center,
  52. children: [
  53. const Text('请输入验证码'),
  54. const SizedBox(
  55. height: 30,
  56. ),
  57. // Implement 4 input fields
  58. Row(
  59. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  60. children: [
  61. OtpInput(_fieldOne, true),
  62. OtpInput(_fieldTwo, false),
  63. OtpInput(_fieldThree, false),
  64. OtpInput(_fieldFour, false)
  65. ],
  66. ),
  67. const SizedBox(
  68. height: 30,
  69. ),
  70. ElevatedButton(
  71. onPressed: () {
  72. setState(() {
  73. _otp = _fieldOne.text +
  74. _fieldTwo.text +
  75. _fieldThree.text +
  76. _fieldFour.text;
  77. });
  78. },
  79. child: const Text('提交')),
  80. const SizedBox(
  81. height: 30,
  82. ),
  83. // Display the entered OTP code
  84. Text(
  85. _otp ?? '验证码',
  86. style: const TextStyle(fontSize: 30),
  87. )
  88. ],
  89. ),
  90. );
  91. }
  92. }
  93. // Create an input widget that takes only one digit
  94. class OtpInput extends StatelessWidget {
  95. final TextEditingController controller;
  96. final bool autoFocus;
  97. const OtpInput(this.controller, this.autoFocus, {Key? key}) : super(key: key);
  98. @override
  99. Widget build(BuildContext context) {
  100. return SizedBox(
  101. height: 60,
  102. width: 50,
  103. child: TextField(
  104. autofocus: autoFocus,
  105. textAlign: TextAlign.center,
  106. keyboardType: TextInputType.number,
  107. controller: controller,
  108. maxLength: 1,
  109. cursorColor: Theme.of(context).primaryColor,
  110. decoration: const InputDecoration(
  111. border: OutlineInputBorder(),
  112. counterText: '',
  113. hintStyle: TextStyle(color: Colors.black, fontSize: 20.0)),
  114. onChanged: (value) {
  115. if (value.length == 1) {
  116. FocusScope.of(context).nextFocus();
  117. }
  118. },
  119. ),
  120. );
  121. }
  122. }

使用第三个包

为了仅用几行代码快速实现您的目标,您可以使用第三方插件。在我们的例子中一些好的是pin_code_fields,otp_text_field等。 下面的例子将使用pin_code_fileds,它提供了很多很棒的功能:

image-20211220134456679

  • 自动将下一个字段集中在打字上,将上一个字段集中在委派上
  • 可以设置为任意长度
  • 高度可定制
  • 输入文本的 3 种不同类型的动画
  • 动画活动、非活动、选定和禁用字段颜色切换
  • 自动对焦选项
  • 从剪贴板粘贴 OTP 代码

您还可以在终端窗口中看到您输入的字符:

img

代码

1.安装插件:

  1. flutter pub add pin_code_fields

2.最终代码:

  1. import 'dart:math' as math;
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:async/async.dart';
  5. import 'package:pin_code_fields/pin_code_fields.dart';
  6. import 'package:url_strategy/url_strategy.dart';
  7. void main() {
  8. setPathUrlStrategy();
  9. runApp(MyApp());
  10. }
  11. class MyApp extends StatelessWidget {
  12. const MyApp({Key? key}) : super(key: key);
  13. @override
  14. Widget build(BuildContext context) {
  15. return MaterialApp(
  16. // Hide the debug banner
  17. debugShowCheckedModeBanner: false,
  18. title: '坚果',
  19. theme: ThemeData(
  20. primarySwatch: Colors.indigo,
  21. ),
  22. home: const HomeScreen(),
  23. );
  24. }
  25. }
  26. class HomeScreen extends StatefulWidget {
  27. const HomeScreen({Key? key}) : super(key: key);
  28. @override
  29. State<HomeScreen> createState() => _HomeScreenState();
  30. }
  31. class _HomeScreenState extends State<HomeScreen> {
  32. String _imageUrl =
  33. 'https://luckly007.oss-cn-beijing.aliyuncs.com/image/image-20211124085239175.png';
  34. double _fontSize = 20;
  35. String _title = "坚果公众号";
  36. // 4 text editing controllers that associate with the 4 input fields
  37. TextEditingController textEditingController = TextEditingController();
  38. String currentText = "";
  39. @override
  40. Widget build(BuildContext context) {
  41. return Scaffold(
  42. appBar: AppBar(
  43. title: Text(_title),
  44. ),
  45. body: Padding(
  46. padding: const EdgeInsets.all(30),
  47. child: Center(
  48. child: PinCodeTextField(
  49. length: 6,
  50. obscureText: false,
  51. animationType: AnimationType.fade,
  52. pinTheme: PinTheme(
  53. shape: PinCodeFieldShape.box,
  54. borderRadius: BorderRadius.circular(5),
  55. fieldHeight: 50,
  56. fieldWidth: 40,
  57. activeFillColor: Colors.white,
  58. ),
  59. animationDuration: const Duration(milliseconds: 300),
  60. backgroundColor: Colors.blue.shade50,
  61. enableActiveFill: true,
  62. controller: textEditingController,
  63. onCompleted: (v) {
  64. debugPrint("Completed");
  65. },
  66. onChanged: (value) {
  67. debugPrint(value);
  68. setState(() {
  69. currentText = value;
  70. });
  71. },
  72. beforeTextPaste: (text) {
  73. return true;
  74. },
  75. appContext: context,
  76. ),
  77. ),
  78. ),
  79. );
  80. }
  81. }

结论

我们已经介绍了 2 个在 Flutter 中创建现代优雅的 完美的验证码输入框/PIN 输入字段的示例。

关于作者:

坚果,目前是华为云享专家,51CTO 博客首席体验官,专注于大前端技术的分享,包括 Flutter,小程序,安卓,VUE,JavaScript。公众号有更多细节。

标签: flutter android 前端

本文转载自: https://blog.csdn.net/qq_39132095/article/details/122120384
版权归原作者 坚果前端の博客 所有, 如有侵权,请联系我们删除。

“Flutter 完美的验证码输入框(2 种方法)”的评论:

还没有评论