Flutter验证码输入框的2种方法实现

 更新时间:2021年12月24日 16:11:51   作者:坚果前端の博客  
本文主要介绍了Flutter验证码输入框的2种方法实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

重点是什么?

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

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

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

从头开始制作 OTP 字段

应用预览

image-20211220134159049

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

以下是它的工作原理:

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

代码

创建一个名为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 中的完整源代码和解释(我将OtpInput类放在文件底部):

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: '坚果',
      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 = "坚果公众号";
  // 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('请输入验证码'),
          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 ?? '验证码',
            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();
          }
        },
      ),
    );
  }
}

使用第三个包

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

image-20211220134456679

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

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

img

代码

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: '坚果',
      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 = "坚果公众号";
  // 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,
          ),
        ),
      ),
    );
  }
}

结论

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

到此这篇关于Flutter验证码输入框的2种方法实现的文章就介绍到这了,更多相关Flutter验证码输入框内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MyBatis查询、新增、更新与删除操作指南

    MyBatis查询、新增、更新与删除操作指南

    这篇文章主要给大家介绍了关于MyBatis查询、新增、更新与删除操作的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用MyBatis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-06-06
  • Mybatis动态SQL之if、choose、where、set、trim、foreach标记实例详解

    Mybatis动态SQL之if、choose、where、set、trim、foreach标记实例详解

    动态SQL就是动态的生成SQL。接下来通过本文给大家介绍Mybatis动态SQL之if、choose、where、set、trim、foreach标记实例详解的相关知识,感兴趣的朋友一起看看吧
    2016-09-09
  • Java I/O深入学习之File和RandomAccessFile

    Java I/O深入学习之File和RandomAccessFile

    这篇文章主要介绍了Java I/O深入学习之File和RandomAccessFile, I/O系统即输入/输出系统,对于一门程序语言来说,创建一个好的输入/输出系统并非易事。在充分理解Java I/O系统以便正确地运用之前,我们需要学习相当数量的类。,需要的朋友可以参考下
    2019-06-06
  • Springboot Thymeleaf字符串对象实例解析

    Springboot Thymeleaf字符串对象实例解析

    这篇文章主要介绍了Springboot Thymeleaf字符串对象实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2007-09-09
  • 一篇文章教你将JAVA的RabbitMQz与SpringBoot整合

    一篇文章教你将JAVA的RabbitMQz与SpringBoot整合

    这篇文章主要介绍了如何将JAVA的RabbitMQz与SpringBoot整合,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-09-09
  • 深入理解JSON及其在Java中的应用小结

    深入理解JSON及其在Java中的应用小结

    json它是一种轻量级的数据交换格式,由于其易于阅读和编写,同时也易于机器解析和生成,因此广泛应用于网络数据交换和配置文件,这篇文章主要介绍了深入理解JSON及其在Java中的应用,需要的朋友可以参考下
    2023-12-12
  • Spring Boot面试题总结

    Spring Boot面试题总结

    这篇文章主要介绍了Spring Boot面试题总结,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • tio-boot整合hotswap-classloader实现热加载方法实例

    tio-boot整合hotswap-classloader实现热加载方法实例

    这篇文章主要为大家介绍了tio-boot整合hotswap-classloader实现热加载方法实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Java如何实现保证线程安全

    Java如何实现保证线程安全

    这篇文章主要介绍了Java如何实现保证线程安全问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04
  • Java 8 Stream filter流式过滤器详解

    Java 8 Stream filter流式过滤器详解

    本文介绍了Java 8的Stream API中的filter方法,展示了如何使用lambda表达式根据条件过滤流式数据,通过实际代码示例,展示了filter方法的高效性以及如何结合findAny和orElse方法处理更复杂的情况,适合Java新手和追求代码优雅的开发者阅读,感兴趣的朋友一起看看吧
    2025-02-02

最新评论