考虑最周全的flutter短信验证登录模块



csdn博客文章 NO.1

前言:

            今天讲述的最主要的内容是login,也就是flutter登录验证模块,很多的小伙伴觉得登记验证不就是那么回事,发送验证码,在60秒之内判断验证码是否正确,对的就登录,不对从新获取。从主题的框架来看,的确是这样的,但是在用户登录的时候,能够做到比较有交互的,人性的,那么在处理一些逻辑上面可能就要废点功夫了。我不喜欢把一些东西讲的云里雾里,其实一些难的东西,无非就是你不知道嘛,你知道的话那么还存在难点吗?首先我把这个登录模块用到的一些主要知识点,我罗列一下,大家可以做个小Dome玩一玩。


记得在《三体》里面听到过一句话,西方文明之所以比东方文明要发展的先进,是因为西方文明懂得做个例拆分


提示:以下是本篇文章正文内容,下面案例可供参考

一、这个登录模块用到了什么?

  • 登录模块肯定要有提示框(我们这里采用 fluttertoast
  • 阿里巴巴第三方短信(没有用过的可以省略)
  • 短信验证框(一位大神写的,不过被我修改一丢丢源码,千万不要慌的😘非常之简单 flutter_verification_box )
  • flutter的input输入框 TextFeild
  • flutter切换动态组件StatefulWidget
  • 最后就是自己分装的路由,非常经典,非常好用哦!

二、组件详情介绍


1.自己封装的路由,大家可以当成一个工具类使用

代码如下(源代码):

import 'dart:async';
import 'package:flutter/material.dart';
class RouteHelper {
  static Future<T> push<T>(BuildContext context, Widget widget) {
    return Navigator.of(context).push(MaterialPageRoute(builder: (ctx) => widget));
  }
  ///删除当前的实例replaceCurrent
  static Future<T> pushReplacement<T>(BuildContext context, Widget widget) {
    return Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (ctx) => widget));
  }
  ///删除先前的所有实例replaceRoot
  static Future<T> pushReplaceRoot<T>(BuildContext context, Widget widget) {
    return Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (ctx) => widget), (Route<dynamic> route) => false);
  }
}

2.封装输入手机号的表单

代码如下(示例):


class MyLoginButton extends StatelessWidget {
  //登录按钮上下左右的距离
  double left;
  double right;
  double bottom;
  double top;
  double all;
  //按钮的透明图
  double opacity;
  Color color;
  //按钮中间显示的文字
  String text;
  //点击时的回调函数
  final GestureTapCallback onTap;

  MyLoginButton({
    this.color = MyColor.inputColor,
    this.text = "登录",//默认中间的字是登陆
    this.opacity = 1,
    this.onTap,
    this.all = 0,
    this.top = 0,
    this.bottom = 0,
    this.right = 28,//默认距离
    this.left = 28,
  });

  @override
  Widget build(BuildContext context) {
    return Opacity(
      opacity: this.opacity,
      child: InkWell(
          child: Container(
            margin: all != 0
                ? EdgeInsets.all(all)
                    : EdgeInsets.fromLTRB(
                        this.left, this.top, this.right, this.bottom),
            height: ScreenUtil().setHeight(60),
            decoration: BoxDecoration(
                color: this.color, borderRadius: BorderRadius.circular(5)),
            child: Center(
              child: Text(
                this.text,
                style: TextStyle(
                 //这个是我方便使用的颜色,大家可以随意使用其他的颜色
                  color: MyColor.inputBcColor,
                  fontSize: 16,
                ),
              ),
            ),
          ),
          onTap: this.onTap
      ),
    );
  }
}



3.提示框

代码如下(示例):
所有的第三方组件地址 :https://pub.flutter-io.cn/flutter/packages?q=fluttertoast

//先去get下来
fluttertoast: ^8.0.4

               //先去做个Dome,按钮点击事件,把这段代码放在里面            
               Fluttertoast.showToast(
                      msg: "请输入正确的手机号",
                      toastLength: Toast.LENGTH_LONG,
                      gravity: ToastGravity.TOP,
                      timeInSecForIosWeb: 1,
                      backgroundColor: Colors.red,
                      textColor: Colors.white,
                      fontSize: 16.0,
                  );

               //---------------------------------------------------------------------   
               
                Fluttertoast.showToast(
                msg: "网络不稳定", 
                gravity: ToastGravity.CENTER
                );


3.大神写的短信验证框


代码如下(示例):

pub文件(源代码):

 //pub一下
 flutter_verification_box: ^1.0.4

业务需求短信验证框的核心代码:

  Container(
           padding: EdgeInsets.only(left: 15,right: 15),
           height: ScreenUtil().setHeight(50),
           child: VerificationBox(
             count: 4,
             itemWidget:ScreenUtil().setHeight(50),
             showCursor: true,
             cursorColor: MyColor.inputColor,
             focusBorderColor: MyColor.inputColor,
             textStyle: TextStyle(fontSize: ScreenUtil().setSp(28),fontWeight: FontWeight.w600),
             onSubmitted: (code){
               showCode(code);
             },
           ),
         )

对业务有特殊的需求,改完之后的源码:

 library flutter_verification_box;

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_verification_box/src/verification_box_item.dart';

///
/// 验证码输入框
///
class VerificationBox extends StatefulWidget {
  VerificationBox(
      {this.count = 6,
      this.itemWidget = 45,
      this.onSubmitted,
      this.type = VerificationBoxItemType.box,
      this.decoration,
      this.borderWidth = 2.0,
      this.borderRadius = 5.0,
      this.textStyle,
      this.focusBorderColor,
      this.borderColor,
      this.unfocus = true,
      this.autoFocus = true,
      this.showCursor = false,
      this.cursorWidth = 2,
      this.cursorColor,
      this.cursorIndent = 10,
      this.cursorEndIndent = 10,
      this.isFllu = true  // <====================================== 这里被改过
      });

  ///
  /// 几位验证码,一般6位,还有4位的
  ///
  final int count;

  ///
  /// 没一个item的宽
  ///
  final double itemWidget;

  ///
  /// 输入完成回调
  ///
  final ValueChanged onSubmitted;

  ///
  /// 每个item的装饰类型,[VerificationBoxItemType]
  ///
  final VerificationBoxItemType type;

  ///
  /// 每个item的样式
  ///
  final Decoration decoration;

  ///
  /// 边框宽度
  ///
  final double borderWidth;

  ///
  /// 边框颜色
  ///
  final Color borderColor;

  ///
  /// 获取焦点边框的颜色
  ///
  final Color focusBorderColor;

  ///
  /// [VerificationBoxItemType.box] 边框圆角
  ///
  final double borderRadius;

  ///
  /// 文本样式
  ///
  final TextStyle textStyle;

  ///
  /// 输入完成后是否失去焦点,默认true,失去焦点后,软键盘消失
  ///
  final bool unfocus;

  ///
  /// 是否自动获取焦点
  ///
  final bool autoFocus;

  ///
  /// 是否显示光标
  ///
  final bool showCursor;

  ///
  /// 光标颜色
  ///
  final Color cursorColor;

  ///
  /// 光标宽度
  ///
  final double cursorWidth;

  ///
  /// 光标距离顶部距离
  ///
  final double cursorIndent;

  ///
  /// 光标距离底部距离
  ///
  final double cursorEndIndent;
  ///
  /// 是否要满足位数才返回   
  ///
  
  final bool isFllu;//   <====================================== 这里被改过
  @override
  State<StatefulWidget> createState() => _VerificationBox();
}

class _VerificationBox extends State<VerificationBox> {
  TextEditingController _controller;

  FocusNode _focusNode;

  List _contentList = [];

  @override
  void initState() {
    List.generate(widget.count, (index) {
      _contentList.add('');
    });
    _controller = TextEditingController();
    _focusNode = FocusNode();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        FocusScope.of(context).requestFocus(_focusNode);
      },
      child: Stack(
        children: <Widget>[

          Positioned.fill(
              child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: List.generate(widget.count, (index) {
              return Container(
                width: widget.itemWidget,
                child: VerificationBoxItem(
                  data: _contentList[index],
                  textStyle: widget.textStyle,
                  type: widget.type,
                  decoration: widget.decoration,
                  borderRadius: widget.borderRadius,
                  borderWidth: widget.borderWidth,
                  borderColor: (_controller.text.length == index
                          ? widget.focusBorderColor
                          : widget.borderColor) ??
                      widget.borderColor,
                  showCursor: widget.showCursor && _controller.text.length == index,
                  cursorColor: widget.cursorColor,
                  cursorWidth: widget.cursorWidth,
                  cursorIndent: widget.cursorIndent,
                  cursorEndIndent: widget.cursorEndIndent,
                ),
              );
            }),
          )),
          _buildTextField(),
        ],
      ),
    );
  }

  ///
  /// 构建TextField
  ///
  _buildTextField() {
    return TextField(
      controller: _controller,
      focusNode: _focusNode,
      decoration: InputDecoration(
        border: UnderlineInputBorder(
            borderSide: BorderSide(color: Colors.transparent)),
        enabledBorder: UnderlineInputBorder(
            borderSide: BorderSide(color: Colors.transparent)),
        focusedBorder: UnderlineInputBorder(
            borderSide: BorderSide(color: Colors.transparent)),
      ),
      cursorWidth: 0,
      autofocus: widget.autoFocus,
      inputFormatters: [
        WhitelistingTextInputFormatter(RegExp("[0-9]")),
      ],
      maxLength: widget.count,
      buildCounter: (
        BuildContext context, {
        int currentLength,
        int maxLength,
        bool isFocused,
      }) {
        return Text('');
      },
      keyboardType: TextInputType.number,
      style: TextStyle(color: Colors.transparent),
      onChanged: _onValueChange,
    );
  }

  _onValueChange(value) {
    for (int i = 0; i < widget.count; i++) {
      if (i < value.length) {
        _contentList[i] = value.substring(i, i + 1);
      } else {
        _contentList[i] = '';
      }
    }
    setState(() {});
    if(widget.isFllu){
      widget.onSubmitted(value);
    }
    if (value.length == widget.count) {
      if (widget.unfocus) {
        _focusNode.unfocus();
      }
      if (widget.onSubmitted != null) {
        widget.onSubmitted(value);
      }
    }
  }
}



4.原生的http

代码如下(示例):

 import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:convert';

_get() async {

  print("_get---");
  var url = 'https://jsonplaceholder.typicode.com/posts/1';
  var httpClient = new HttpClient();

  String result;
  try {
    var request = await httpClient.getUrl(Uri.parse(url));
    var response = await request.close();
    print("statusCode----${response.statusCode}");

    if (response.statusCode == HttpStatus.ok) {
      var responseBody = await response.transform(utf8.decoder).join();
      var json = responseBody;
      var data = jsonDecode(json);

      print(data.toString());
      print("data----$data");

      result = 'HttpStatus.ok';

    } else {
      result = 'Error getting IP address:\nHttp status ${response.statusCode}';
    }

  } catch (exception) {
    result = 'Failed getting IP address';
  }

  print("result----$result");
}



_post() async {

  print("_post---");
  var httpClient = new HttpClient();

  String result;
  try {
    var url = "http://api.juheapi.com/japi/toh";
    var request = await httpClient.postUrl(Uri.parse(url));
    // 添加请求体
    Map jsonMap = {'shopperId': 9356,'machineId':5117,'orderType':2,'orderId':108};

    Map<String, String> map1 = new Map();
    map1["v"] = "1.0";
    map1["month"] = "7";
    map1["day"] = "25";
    map1["key"] = "bd6e35a2691ae5bb8425c8631e475c2a";

    request.add(utf8.encode(json.encode(map1)));

    HttpClientResponse response = await request.close();
    String responseBody = await response.transform(utf8.decoder).join();
    print("statusCode----${response.statusCode}");

    if (response.statusCode == HttpStatus.ok) {
      print('请求成功');
      print(response.headers);//打印头部信息
      print("post------$responseBody");

      result = 'HttpStatus.ok';

    } else {
      result = 'Error getting IP address:\nHttp status ${response.statusCode}';
    }

  } catch (exception) {
    result = 'Failed getting IP address';
  }

  print("result----$result");
}


class HttpClientTest extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return new Scaffold(
      appBar: new AppBar(
        title: new Text('HttpClientTest'),
      ),

      body: Center(
        child:Column(

          children: <Widget>[

            SizedBox(height: 32.0),

            Text("HttpClient Get Post 练习"),

            SizedBox(height: 32.0),

            RaisedButton(
              onPressed: _get,
              child: new Text('Get 请求'),
            ),


            RaisedButton(
              onPressed: _post,
              child: new Text('Post 请求'),
            ),

          ],

        ),
      ),


    );
  }
}

 

总结

             好了,以上就是大家的武器了,一定要多去尝试,其他的业务逻辑,下一篇在讲的🥰🥰🥰🥰
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值