首頁 > 軟體

Flutter實現滑動塊驗證碼功能

2022-03-23 19:00:11

Flutter實現滑動塊驗證碼功能,供大家參考,具體內容如下

本文實現的是一個用於登入時,向右滑動滑動塊到最右邊完成驗證的一個功能。當滑動未到最右邊時,滑動塊回彈回左邊起始位置。

import 'package:flutter/material.dart';
 
class SlideVerifyWidget extends StatefulWidget{
 
  /// 背景色
  final Color backgroundColor;
  /// 滑動過的顏色
  final Color slideColor;
  /// 邊框顏色
  final Color borderColor;
 
  final double height;
  final double width;
 
  final VoidCallback verifySuccessListener;
 
  const SlideVerifyWidget({
    Key key,
    this.backgroundColor = Colors.blueGrey,
    this.slideColor = Colors.green,
    this.borderColor = Colors.grey,
    this.height = 44,
    this.width = 240,
    this.verifySuccessListener
  }) : super(key: key);
 
  @override
  State<StatefulWidget> createState() {
    return SlideVerifyState();
  }
 
}
 
class SlideVerifyState extends State<SlideVerifyWidget> with TickerProviderStateMixin{
 
  double height;
  double width ;
 
  double sliderDistance = 0;
 
  double initial = 0.0;
 
  /// 滑動塊寬度
  double sliderWidth = 64;
 
  /// 驗證是否通過,滑動到最右方為通過
  bool verifySuccess = false;
 
  /// 是否允許拖動
  bool enableSlide = true;
 
  AnimationController _animationController;
  Animation _curve;
 
  @override
  void initState() {
    super.initState();
    this.width = widget.width;
    this.height = widget.height;
    _initAnimation();
  }
 
  @override
  void dispose() {
    _animationController?.dispose();
    super.dispose();
  }
 
 
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onHorizontalDragStart: (DragStartDetails details){
        if(!enableSlide){
          return;
        }
        initial = details.globalPosition.dx;
      },
      onHorizontalDragUpdate: (DragUpdateDetails details){
        if(!enableSlide){
          return;
        }
        sliderDistance = details.globalPosition.dx - initial;
        if(sliderDistance < 0){
          sliderDistance = 0;
        }
        /// 當滑動到最右邊時,通知驗證成功,並禁止滑動
        if(sliderDistance > width - sliderWidth){
          sliderDistance = width - sliderWidth;
          enableSlide = false;
          verifySuccess = true;
          if(widget.verifySuccessListener != null){
            widget.verifySuccessListener();
          }
        }
        setState(() {
        });
      },
      onHorizontalDragEnd: (DragEndDetails details){
        /// 滑動鬆開時,如果未達到最右邊,啟動回彈動畫
        if(enableSlide){
          enableSlide = false;
          _animationController.forward();
        }
      },
      child: Container(
        height: height,
        width: width,
        decoration: BoxDecoration(
          color: widget.backgroundColor,
          border: Border.all(color: widget.borderColor),
            /// 圓角實現
          borderRadius: BorderRadius.all(new Radius.circular(height))
        ),
        child: Stack(
          children: <Widget>[
            Positioned(
              top: 0,
              left: 0,
              child: Container(
                height: height - 2,
                /// 當slider滑動到距左邊只有兩三畫素距離時,已滑動背景會有一點點渲染出邊框範圍,
                /// 因此當滑動距離小於1時,直接將寬度設定為0,解決滑動塊返回左邊時導致的綠色閃動,但如果是緩慢滑動到左邊該問題仍沒解決
                width: sliderDistance < 1? 0 : sliderDistance + sliderWidth / 2,
                decoration: BoxDecoration(
                    color: widget.slideColor,
                    /// 圓角實現
                    borderRadius: BorderRadius.all(new Radius.circular(height / 2))
                ),
              ),
            ),
            Center(
              child: Text(verifySuccess?"驗證成功":"請按住滾軸,拖動到最右邊", style: TextStyle(color: verifySuccess?Colors.white:Colors.black54, fontSize: 14),),
            ),
            Positioned(
              top: 0,
              /// 此處將sliderDistance距離往左偏2是解決當滑動塊滑動到最右邊時遮擋外部邊框
              left: sliderDistance > sliderWidth ? sliderDistance - 2 : sliderDistance,
              child: Container(
                width: sliderWidth,
                height: height - 2 ,
                alignment: Alignment.center,
                decoration: BoxDecoration(
                    color: Colors.white,
                    border: Border.all(color: widget.borderColor),
                    /// 圓角實現
                    borderRadius: BorderRadius.all(new Radius.circular(height))
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    SizedBox(width: 6,),
                    Image.asset("assets/images/ic_safety.png", height: 24, width: 24,),
                    Image.asset("assets/images/ic_next_primary.png", height: 16, width: 16,),
                    /// 因為向右箭頭有透明邊距導致兩個箭頭間隔過大,因此將第二個箭頭向左偏移,如果切圖無邊距則不用偏移
                    Transform(
                      transform: Matrix4.translationValues(-8, 0, 0),
                      child: Image.asset("assets/images/ic_next_primary.png", height: 16, width: 16,),
                    ),
                  ],
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
 
  /// 回彈動畫
  void _initAnimation(){
    _animationController = AnimationController(
        duration: const Duration(milliseconds: 300), vsync: this);
    _curve = CurvedAnimation(parent: _animationController, curve: Curves.easeOut);
    _curve.addListener(() {
      setState(() {
        sliderDistance = sliderDistance - sliderDistance * _curve.value;
        if(sliderDistance <= 0){
          sliderDistance = 0;
        }
      });
    });
    _animationController.addStatusListener((status) {
      if(status == AnimationStatus.completed){
        enableSlide = true;
        _animationController.reset();
      }
    });
  }
 
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com