Flutter 短信验证码组件

效果图

效果图

思路

因为需要弹出键盘,所以使用了一个隐藏的 TextField,通过点击事件捕获焦点,方块只做展示使用。

组件代码

import 'package:bubble_mobile/util/func_utils.dart';
import 'package:bubble_mobile/util/size_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class VerifyCodeWidget extends StatefulWidget {
  final int count;
  final Color backgroundColor;
  final Color frontgroundColor;
  final TVoidCallback onValueChanged;
  final double aspectRatio;
  final int gapRatio;
  final bool autoFocus;
  final bool autoUnfocus;
  final double borderRadius;
  final double padding;

  VerifyCodeWidget(
      {required this.count,
      required this.backgroundColor,
      required this.frontgroundColor,
      required this.onValueChanged,
      this.aspectRatio = 1,
      this.gapRatio = 7,
      this.autoFocus = true,
      this.autoUnfocus = true,
      double? borderRadius,
      double? padding,
      super.key})
      : borderRadius = borderRadius ?? SizeUtils.blockWidth * 2,
        padding = padding ?? borderRadius ?? SizeUtils.blockWidth * 3;

  @override
  State<VerifyCodeWidget> createState() => _VerifyCodeWidgetState();
}

class _VerifyCodeWidgetState extends State<VerifyCodeWidget> {
  String _verifyCode = "";
  final FocusNode _hideInputerFocus = FocusNode();

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.topLeft,
      children: [
        Visibility(
            visible: false,
            maintainState: true,
            maintainSize: false,
            maintainAnimation: false,
            child: TextField(
              keyboardType: TextInputType.number,
              maxLength: widget.count,
              maxLengthEnforcement:
                  MaxLengthEnforcement.truncateAfterCompositionEnds,
              maxLines: 1,
              focusNode: _hideInputerFocus,
              onChanged: (v) {
                if (widget.autoUnfocus && v.length == widget.count) {
                  _hideInputerFocus.unfocus();
                }
                setState(() {
                  _verifyCode = v;
                  widget.onValueChanged.call(v);
                });
              },
            )),
        GestureDetector(
            onTap: () => _hideInputerFocus.requestFocus(),
            child: Container(
              color: widget.backgroundColor,
              child: Row(
                children: [
                  for (var i = 0; i < widget.count; ++i) ...[
                    Expanded(
                      flex: widget.gapRatio,
                      child: AspectRatio(
                          aspectRatio: widget.aspectRatio,
                          child: Container(
                            decoration: BoxDecoration(
                                color: widget.frontgroundColor,
                                borderRadius:
                                    BorderRadius.circular(widget.borderRadius)),
                            child: Padding(
                              padding: EdgeInsets.all(widget.padding),
                              child: FittedBox(
                                fit: BoxFit.fitHeight,
                                child: Text(
                                    i < _verifyCode.length
                                        ? _verifyCode[i]
                                        : "",
                                    style: TextStyle(
                                        color: widget.backgroundColor)),
                              ),
                            ),
                          )),
                    ),
                    i < widget.count - 1
                        ? Expanded(
                            flex: 1,
                            child: Container(color: Colors.transparent))
                        : Container(width: 0, color: Colors.transparent)
                  ],
                ],
              ),
            ))
      ],
    );
  }
}

组件使用

VerifyCodeWidget(
            count: 6,
            backgroundColor: ColorUtils.enableBackground,
            frontgroundColor: ColorUtils.mainTheme,
            onValueChanged: (v) => _verifyCode = v,
            autoFocus: false)
posted @ 2022-10-31 21:12  seliote  阅读(58)  评论(0)    收藏  举报