当前位置:主页 > 移动开发 > Android代码 >

Flutter实现滑动块验证码功能

时间:2023-01-30 10:34:46 | 栏目:Android代码 | 点击:

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();
      }
    });
  }
 
}

您可能感兴趣的文章:

相关文章