最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Flutter版本的自定義短信驗(yàn)證碼實(shí)現(xiàn)示例解析

 更新時(shí)間:2023年08月03日 10:03:02   作者:龍之音  
這篇文章主要介紹了Flutter版本的自定義短信驗(yàn)證碼實(shí)現(xiàn)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

效果圖(Flutter版本)

簡介

前幾天我發(fā)布了一個(gè)Android版本的短信驗(yàn)證碼,今天發(fā)布Flutter版本,其實(shí)實(shí)現(xiàn)思路和原生版本是一模一樣,可以說是直接把原生的繪制代碼復(fù)制粘貼到Flutter項(xiàng)目中,kt修改為dart,實(shí)現(xiàn)樣式還是下面四種:

  • 表格類型
  • 方塊類型
  • 橫線類型
  • 圈圈類型

所以這里就不在闡述實(shí)現(xiàn)思路了,你也可以直接查看Android版本,點(diǎn)擊

Android-自定義短信驗(yàn)證碼

這里直接上全部代碼,一把梭~

代碼

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/*
 * 模式
 */
enum CodeMode {
  //文字
  text
}
/*
 * 樣式
 */
enum CodeStyle {
  //表格
  form,
  //方塊
  rectangle,
  //橫線
  line,
  //圈圈
  circle
}
/*
 * 驗(yàn)證碼
 */
class CodeWidget extends StatefulWidget {
  CodeWidget({
    Key? key,
    this.maxLength = 4,
    this.height = 50,
    this.mode = CodeMode.text,
    this.style = CodeStyle.form,
    this.codeBgColor = Colors.transparent,
    this.borderWidth = 2,
    this.borderColor = Colors.grey,
    this.borderSelectColor = Colors.red,
    this.borderRadius = 3,
    this.contentColor = Colors.black,
    this.contentSize = 16,
    this.itemWidth = 50,
    this.itemSpace = 16,
  }) : super(key: key) {
    //如果是表格樣式,就不設(shè)置Item之間的距離
    if (style == CodeStyle.form) {
      itemSpace = 0;
    }
  }
  late int maxLength;
  //高度
  late double height;
  //驗(yàn)證碼模式
  late CodeMode mode;
  //驗(yàn)證碼樣式
  late CodeStyle style;
  //背景色
  late Color codeBgColor;
  //邊框?qū)挾?
  late double borderWidth;
  //邊框默認(rèn)顏色
  late Color borderColor;
  //邊框選中顏色
  late Color borderSelectColor;
  //邊框圓角
  late double borderRadius;
  //內(nèi)容顏色
  late Color contentColor;
  //內(nèi)容大小
  late double contentSize;
  // 單個(gè)Item寬度
  late double itemWidth;
  //Item之間的間隙
  late int itemSpace;
  @override
  State<CodeWidget> createState() => _CodeWidgetState();
}
class _CodeWidgetState extends State<CodeWidget> {
  FocusNode focusNode = FocusNode();
  TextEditingController controller = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: widget.height,
      child: LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
          var size = Size(constraints.maxWidth, constraints.maxHeight);
          return CustomPaint(
            size: size,
            painter: CodeCustomPainter(
              widget.maxLength,
              size.width,
              size.height,
              widget.mode,
              widget.style,
              widget.codeBgColor,
              widget.borderWidth,
              widget.borderColor,
              widget.borderSelectColor,
              widget.borderRadius,
              widget.contentColor,
              widget.contentSize,
              widget.itemWidth,
              widget.itemSpace,
              focusNode,
              controller,
            ),
            child: TextField(
              //控制焦點(diǎn)
              focusNode: focusNode,
              controller: controller,
              //光標(biāo)不顯示
              showCursor: false,
              //光標(biāo)顏色透明
              cursorColor: Colors.transparent,
              enableInteractiveSelection: false,
              //設(shè)置最大長度
              maxLength: widget.maxLength,
              //文字樣式為透明
              style: const TextStyle(
                color: Colors.transparent,
              ),
              //只允許數(shù)據(jù)數(shù)字
              inputFormatters: [
                FilteringTextInputFormatter.digitsOnly,
              ],
              //彈出數(shù)字鍵盤
              keyboardType: TextInputType.number,
              //邊框樣式取消
              decoration: null,
            ),
          );
        },
      ),
    );
  }
}
class CodeCustomPainter extends CustomPainter {
  double width;
  double height;
  int maxLength;
  //驗(yàn)證碼模式
  late CodeMode mode;
  //驗(yàn)證碼樣式
  late CodeStyle style;
  //背景色
  Color codeBgColor;
  //邊框?qū)挾?
  double borderWidth;
  //邊框默認(rèn)顏色
  Color borderColor;
  //邊框選中顏色
  Color borderSelectColor;
  //邊框圓角
  double borderRadius;
  //內(nèi)容顏色
  Color contentColor;
  //內(nèi)容大小
  double contentSize;
  // 單個(gè)Item寬度
  double itemWidth;
  //Item之間的間隙
  int itemSpace;
  //焦點(diǎn)
  FocusNode focusNode;
  TextEditingController controller;
  //線路畫筆
  late Paint linePaint;
  //文字畫筆
  late TextPainter textPainter;
  //當(dāng)前文字索引
  int currentIndex = 0;
  //左右間距值
  double space = 0;
  CodeCustomPainter(
    this.maxLength,
    this.width,
    this.height,
    this.mode,
    this.style,
    this.codeBgColor,
    this.borderWidth,
    this.borderColor,
    this.borderSelectColor,
    this.borderRadius,
    this.contentColor,
    this.contentSize,
    this.itemWidth,
    this.itemSpace,
    this.focusNode,
    this.controller,
  ) {
    linePaint = Paint()
      ..color = borderColor
      ..isAntiAlias = true
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round
      ..strokeWidth = borderWidth;
    textPainter = TextPainter(
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );
  }
  @override
  void paint(Canvas canvas, Size size) {
    //當(dāng)前索引(待輸入的光標(biāo)位置)
    currentIndex = controller.text.length;
    //Item寬度(這里判斷如果設(shè)置了寬度并且合理就使用當(dāng)前設(shè)置的寬度,否則平均計(jì)算)
    if (itemWidth != -1 &&
        (itemWidth * maxLength + itemSpace * (maxLength - 1)) <= width) {
      itemWidth = itemWidth;
    } else {
      itemWidth = ((width - itemSpace * (maxLength - 1)) / maxLength);
    }
    //計(jì)算左右間距大小
    space = (width - itemWidth * maxLength - itemSpace * (maxLength - 1)) / 2;
    //繪制樣式
    switch (style) {
      //表格
      case CodeStyle.form:
        _drawFormCode(canvas, size);
        break;
      //方塊
      case CodeStyle.rectangle:
        _drawRectangleCode(canvas, size);
        break;
      //橫線
      case CodeStyle.line:
        _drawLineCode(canvas, size);
        break;
      //圈圈
      case CodeStyle.circle:
        _drawCircleCode(canvas, size);
        break;
      //TODO  拓展
    }
    //繪制文字內(nèi)容
    _drawContentCode(canvas, size);
  }
  /*
   * 繪制表格樣式
   */
  void _drawFormCode(Canvas canvas, Size size) {
    //繪制表格邊框
    Rect rect = Rect.fromLTRB(space, 0, width - space, height);
    RRect rRect = RRect.fromRectAndRadius(rect, Radius.circular(borderRadius));
    linePaint.color = borderColor;
    canvas.drawRRect(rRect, linePaint);
    //繪制表格中間分割線
    for (int i = 1; i < maxLength; i++) {
      double startX = space + itemWidth * i + itemSpace * i;
      double startY = 0;
      double stopY = height;
      canvas.drawLine(Offset(startX, startY), Offset(startX, stopY), linePaint);
    }
    //繪制當(dāng)前位置邊框
    for (int i = 0; i < maxLength; i++) {
      if (currentIndex != -1 && currentIndex == i && focusNode.hasFocus) {
        //計(jì)算每個(gè)表格的左邊距離
        double left = 0;
        if (i == 0) {
          left = (space + itemWidth * i);
        } else {
          left = ((space + itemWidth * i + itemSpace * i));
        }
        linePaint.color = borderSelectColor;
        //第一個(gè)
        if (i == 0) {
          RRect rRect = RRect.fromLTRBAndCorners(
              left, 0, left + itemWidth, height,
              topLeft: Radius.circular(borderRadius),
              bottomLeft: Radius.circular(borderRadius));
          canvas.drawRRect(rRect, linePaint);
        }
        //最后一個(gè)
        else if (i == maxLength - 1) {
          RRect rRect = RRect.fromLTRBAndCorners(
              left, 0, left + itemWidth, height,
              topRight: Radius.circular(borderRadius),
              bottomRight: Radius.circular(borderRadius));
          canvas.drawRRect(rRect, linePaint);
        }
        //其他
        else {
          RRect rRect =
              RRect.fromLTRBAndCorners(left, 0, left + itemWidth, height);
          canvas.drawRRect(rRect, linePaint);
        }
      }
    }
  }
  /*
   * 繪制方塊樣式
   */
  void _drawRectangleCode(Canvas canvas, Size size) {
    for (int i = 0; i < maxLength; i++) {
      double left = 0;
      if (i == 0) {
        left = space + i * itemWidth;
      } else {
        left = space + i * itemWidth + itemSpace * i;
      }
      Rect rect = Rect.fromLTRB(left, 0, left + itemWidth, height);
      RRect rRect =
          RRect.fromRectAndRadius(rect, Radius.circular(borderRadius));
      //當(dāng)前光標(biāo)樣式
      if (currentIndex != -1 && currentIndex == i && focusNode.hasFocus) {
        linePaint.color = borderSelectColor;
        canvas.drawRRect(rRect, linePaint);
      }
      //默認(rèn)樣式
      else {
        linePaint.color = borderColor;
        canvas.drawRRect(rRect, linePaint);
      }
    }
  }
  /*
   * 繪制橫線樣式
   */
  void _drawLineCode(Canvas canvas, Size size) {
    for (int i = 0; i < maxLength; i++) {
      //當(dāng)前選中狀態(tài)
      if (controller.value.text.length == i && focusNode.hasFocus) {
        linePaint.color = borderSelectColor;
      }
      //默認(rèn)狀態(tài)
      else {
        linePaint.color = borderColor;
      }
      double startX = space + itemWidth * i + itemSpace * i;
      double startY = height - borderWidth;
      double stopX = startX + itemWidth;
      double stopY = startY;
      canvas.drawLine(Offset(startX, startY), Offset(stopX, stopY), linePaint);
    }
  }
  /*
   * 繪制圈圈樣式
   */
  void _drawCircleCode(Canvas canvas, Size size) {
    for (int i = 0; i < maxLength; i++) {
      //當(dāng)前繪制的圓圈的左x軸坐標(biāo)
      double left = 0;
      if (i == 0) {
        left = space + i * itemWidth;
      } else {
        left = space + i * itemWidth + itemSpace * i;
      }
      //圓心坐標(biāo)
      double cx = left + itemWidth / 2.0;
      double cy = height / 2.0;
      //圓形半徑
      double radius = itemWidth / 5.0;
      //默認(rèn)樣式
      if (i >= currentIndex) {
        linePaint.style = PaintingStyle.fill;
        canvas.drawCircle(Offset(cx, cy), radius, linePaint);
      }
    }
  }
  /*
   * 繪制驗(yàn)證碼文字
   */
  void _drawContentCode(Canvas canvas, Size size) {
    String textStr = controller.text;
    for (int i = 0; i < maxLength; i++) {
      if (textStr.isNotEmpty && i < textStr.length) {
        switch (mode) {
          case CodeMode.text:
            String code = textStr[i].toString();
            textPainter.text = TextSpan(
              text: code,
              style: const TextStyle(color: Colors.red, fontSize: 30),
            );
            textPainter.layout();
            double x = space +
                itemWidth * i +
                itemSpace * i +
                (itemWidth - textPainter.width) / 2;
            double y = (height - textPainter.height) / 2;
            textPainter.paint(canvas, Offset(x, y));
            break;
          //TODO  拓展
        }
      }
    }
  }
  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

Github:https://github.com/yixiaolunhui/flutter_xy

以上就是Flutter版本的自定義短信驗(yàn)證碼實(shí)現(xiàn)示例解析的詳細(xì)內(nèi)容,更多關(guān)于Flutter 自定義短信驗(yàn)證碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android 極光推送別名與標(biāo)簽方式

    Android 極光推送別名與標(biāo)簽方式

    這篇文章主要介紹了Android 極光推送別名與標(biāo)簽方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • Flutter Android View在鴻蒙系統(tǒng)上的使用指南

    Flutter Android View在鴻蒙系統(tǒng)上的使用指南

    Flutter Android View 是一個(gè)用于在 Android 應(yīng)用中以視圖級(jí)別集成 Flutter 模塊的示例項(xiàng)目,本文給大家介紹了Flutter Android View在鴻蒙系統(tǒng)上的使用指南,需要的朋友可以參考下
    2026-01-01
  • Android自定義ViewGroup實(shí)現(xiàn)淘寶商品詳情頁

    Android自定義ViewGroup實(shí)現(xiàn)淘寶商品詳情頁

    這篇文章主要為大家詳細(xì)介紹了Android自定義ViewGroup實(shí)現(xiàn)淘寶商品詳情頁,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Android進(jìn)階教程之ViewGroup自定義布局

    Android進(jìn)階教程之ViewGroup自定義布局

    這篇文章主要給大家介紹了關(guān)于Android進(jìn)階教程之ViewGroup自定義布局的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • ViewPager實(shí)現(xiàn)圖片切換效果

    ViewPager實(shí)現(xiàn)圖片切換效果

    這篇文章主要為大家詳細(xì)介紹了ViewPager實(shí)現(xiàn)圖片切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Android實(shí)現(xiàn)聊天記錄上傳本地服務(wù)器(即時(shí)通訊)

    Android實(shí)現(xiàn)聊天記錄上傳本地服務(wù)器(即時(shí)通訊)

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)聊天記錄上傳本地服務(wù)器,即時(shí)通訊功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • 微信舉報(bào)解除和微信解除限制的6個(gè)方法

    微信舉報(bào)解除和微信解除限制的6個(gè)方法

    本文主要介紹微信被舉報(bào)怎么解除?微信解除限制,這里整理了6種方法,有需要的小伙伴可以參考下
    2016-09-09
  • Android ScrollView的頂部下拉和底部上拉回彈效果

    Android ScrollView的頂部下拉和底部上拉回彈效果

    本篇文章主要介紹了Android ScrollView的頂部下拉和底部上拉回彈效果,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • Android Retrofit 2.0框架上傳圖片解決方案

    Android Retrofit 2.0框架上傳圖片解決方案

    這篇文章主要介紹了Android Retrofit 2.0框架上傳一張與多張圖片解決方案,感興趣的小伙伴們可以參考一下
    2016-03-03
  • 詳解在Flutter中如何使用dio

    詳解在Flutter中如何使用dio

    應(yīng)用程序開發(fā)的一個(gè)關(guān)鍵部分是優(yōu)雅地處理網(wǎng)絡(luò)請(qǐng)求。網(wǎng)絡(luò)返回的響應(yīng)可能包含意想不到的結(jié)果,為了獲得良好的用戶體驗(yàn),您需要提前處理邊緣情況。本文將詳細(xì)為大家介紹Flutter如何使用dio,需要的可以參考一下
    2022-04-04

最新評(píng)論

九江市| 右玉县| 清新县| 十堰市| 衡水市| 富平县| 洱源县| 嘉荫县| 成都市| 泗水县| 霍城县| 巨野县| 中卫市| 敖汉旗| 龙海市| 郁南县| 南川市| 达州市| 武定县| 星座| 临朐县| 富蕴县| 平武县| 巴青县| 元朗区| 千阳县| 五家渠市| 桂阳县| 大田县| 大石桥市| 温州市| 鲁山县| 阿克| 改则县| 宜城市| 赣榆县| 徐闻县| 吉安市| 萨迦县| 肃宁县| 巨野县|