Flutter 驗證碼倒數計時Widget封裝

謝棟發表於2020-03-04

引言

在日常開發過程中,像倒數計時這樣的場景使用的還是比較多的,比如延時完成一段邏輯,或者在啟動頁先載入一個閃屏廣告,倒數計時間到之後再進入app,更常見的場景就是我們在獲取手機驗證碼時用於友好提示使用者的等待試圖。本次博文我們就一起來了解下基於flutter封裝一個倒數計時widget的全過程

課程知識點

  • 1.關於Timer的使用
  • 2.回撥函式的傳值
  • 3.元件封裝思想的建立

在開始今天的博文之前,先來看下今天課程所講內容的效果圖:

效果圖

在這裡插入圖片描述

邏輯梳理

從上圖我們可以分析得出

1.整個過程倒數計時widget一共分為兩種狀態

  • 倒數計時中:按照我們設定好的時間,每次遞減一秒,直到剩餘時間為0.在此期間按鈕字型顏色為灰色,按鈕不可再次接收點選事件
  • 初始狀態或完成倒數計時:按鈕字型顏色為藍色,點選按鈕進入倒數計時狀態。

2.按鈕上的倒數計時邏輯,我們藉助dart async包下的Timer來完成

Timer.periodic(Duration duration, void callback(Timer timer)) 
複製程式碼

從方法簽名中,我們可以看出,Timer.periodic接收兩個引數,分別為時間間隔,跟回撥函式。我們利用傳入時間間隔為1秒為週期,然後在回撥函式中執行,每次時間減1的操作,如果當前剩餘時間小於1,我們結束當前Timer,否則一直執行回撥函式

    Timer _timer;
    int _countdownTime = 10;

    _timer = Timer.periodic(
        Duration(seconds: 1),
            (Timer timer) =>
        {
          setState(() {
            if (_countdownTime < 1) {
              _timer.cancel();
            } else {
              _countdownTime = _countdownTime - 1;
            }
          })
        });
            
複製程式碼

其他部分涉及到按鈕上狀態跟點選事件的處理在入門進階專欄的系列文章中,我都詳細講解過,這裡就不展開細說了,讀者自行結合程式碼閱讀理解吧。

封裝好的倒數計時Widget程式碼:
import 'dart:async';

import 'package:flutter/material.dart';

/**
 * @desc
 * @author xiedong
 * @date   2020-02-28.
 */

class TimerCountDownWidget extends StatefulWidget {
  Function onTimerFinish;

  TimerCountDownWidget({this.onTimerFinish}) : super();

  @override
  State<StatefulWidget> createState() => TimerCountDownWidgetState();
}

class TimerCountDownWidgetState extends State<TimerCountDownWidget> {
  Timer _timer;
  int _countdownTime = 0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        if (_countdownTime == 0) {
          setState(() {
            _countdownTime = 60;
          });
          //開始倒數計時
          startCountdownTimer();
        }
      },
      child: RaisedButton(
        color: Colors.black12,
        child: Text(
          _countdownTime > 0 ? '$_countdownTime後重新獲取' : '獲取驗證碼',
          style: TextStyle(
            fontSize: 14,
            color: _countdownTime > 0
                ? Colors.white
                : Color.fromARGB(255, 17, 132, 255),
          ),
        ),
      ),
    );
  }

  void startCountdownTimer() {
//    const oneSec = const Duration(seconds: 1);
//    var callback = (timer) => {
//      setState(() {
//        if (_countdownTime < 1) {
//          widget.onTimerFinish();
//          _timer.cancel();
//        } else {
//          _countdownTime = _countdownTime - 1;
//        }
//      })
//    };
//
//    _timer = Timer.periodic(oneSec, callback);


    _timer = Timer.periodic(
        Duration(seconds: 1),
        (Timer timer) => {
              setState(() {
                if (_countdownTime < 1) {
                  widget.onTimerFinish();
                  _timer.cancel();
                } else {
                  _countdownTime = _countdownTime - 1;
                }
              })
            });
  }

  @override
  void dispose() {
    super.dispose();
    if (_timer != null) {
      _timer.cancel();
    }
  }
}

複製程式碼
在頁面中作為Widget使用
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/custom_widget/widget/timer_count_down_widget.dart';

/**
 * @desc
 * @author xiedong
 * @date   2020-02-28.
 */

class VerficationCodePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => VerficationCodePageState();
}

class VerficationCodePageState extends State<VerficationCodePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("驗證碼倒數計時"),
        centerTitle: true,
      ),
      body: Center(
        child: TimerCountDownWidget(onTimerFinish: (){
          print("倒數計時結束--------");
        },),
      ),
    );
  }
}
複製程式碼

執行程式碼後,我們點選獲取驗證碼按鈕,當倒數計時結束後,我們傳入的回撥函式會被呼叫,如下圖在log控制檯列印出我們在程式中輸入的內容:

在這裡插入圖片描述

本次博文相關程式碼:博文原始碼

相關文章