android滑动拼图验证码控件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android滑动拼图验证码控件相关的知识,希望对你有一定的参考价值。

参考技术A package com.yolanda.code.library.widget;

import android.animation.ValueAnimator;

import android.content.Context;

import android.graphics.Bitmap;

import android.os.Handler;

import android.util.AttributeSet;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.AlphaAnimation;

import android.view.animation.Animation;

import android.view.animation.LinearInterpolator;

import android.view.animation.TranslateAnimation;

import android.widget.FrameLayout;

import android.widget.ImageView;

import android.widget.SeekBar;

import android.widget.TextView;

import com.yolanda.code.library.R;

import com.yolanda.code.library.view.DiyStyleTextView;

/**

* @author Created by Yolanda on 2018/10/31.

* @description 滑动拼图验证码

*/

public final class DragImageView extends FrameLayout implements SeekBar.OnSeekBarChangeListener

    private final int showTipsTime = 1500;

    private final int animeTime = 333;

    private final int flashTime = 800;

    private ImageView ivCover;

    private ImageView ivBlock;

    private SeekBar sb;

    private TextView tvTips2;

    private DiyStyleTextView tvTips;

    private View vFlash, flContent;

    private Handler handler = new Handler();

    private Bitmap cover, block, completeCover;

    private boolean isNormal;

    public DragImageView(Context context)

        super(context);

        init();

   

    public DragImageView(Context context, AttributeSet attrs)

        super(context, attrs);

        init();

   

    public DragImageView(Context context, AttributeSet attrs, int defStyle)

        super(context, attrs, defStyle);

        init();

   

    private void init()

        View.inflate(getContext(), R.layout.drag_view, this);

        flContent = findViewById(R.id.drag_fl_content);

        ivCover = findViewById(R.id.drag_iv_cover);

        ivBlock = findViewById(R.id.drag_iv_block);

        tvTips = findViewById(R.id.drag_tv_tips);

        tvTips2 = findViewById(R.id.drag_tv_tips2);

        vFlash = findViewById(R.id.drag_v_flash);

        tvTips.setColorRegex("拼图|成功|失败|正确|[\\d\\.%]+", 0xfff75151);

        sb = findViewById(R.id.drag_sb);

        sb.setMax(getContext().getResources().getDisplayMetrics().widthPixels);

        sb.setOnSeekBarChangeListener(this);

        reset();

   

    /**

    * 设置资源

    *

    * @param cover        拼图

    * @param block        滑块

    * @param completeCover 完成的拼图

    * @param block_y      滑块Y值比例

    */

    public void setUp(Bitmap cover, Bitmap block, Bitmap completeCover, float block_y)

        this.cover = cover;

        this.block = block;

        this.completeCover = completeCover;

        ivCover.setImageBitmap(completeCover);

        ivBlock.setImageBitmap(block);

        setLocation(1f * cover.getWidth() / cover.getHeight(), 1f * block.getHeight() / cover.getHeight(), block_y);

   

    /**

    * 设置比例大小

    *

    * @param cover_wph  图片bili

    * @param block_size 滑块大小占高比

    * @param block_y    滑块位置占高比

    */

    private void setLocation(final float cover_wph, final float block_size, final float block_y)

        post(new Runnable()

            @Override

            public void run()

                final int w = flContent.getMeasuredWidth();

                int h = (int) (w / cover_wph);

                ViewGroup.LayoutParams l = flContent.getLayoutParams();

                l.width = w;

                l.height = h;

                flContent.setLayoutParams(l);

                ViewGroup.MarginLayoutParams l2 = (MarginLayoutParams) ivBlock.getLayoutParams();

                l2.height = (int) (h * block_size);

                l2.width = l2.height * block.getWidth() / block.getHeight();

                l2.topMargin = (int) (h * block_y);

                ivBlock.setLayoutParams(l2);

           

        );

   

    public void ok()

        ivCover.setImageBitmap(completeCover);

        blockHideAnime();

        int penset = (int) (99 - (timeUse > 1 ? timeUse - 1 : 0) / 0.1f);

        if (penset < 1) penset = 1;

        tvTips.setText(String.format("拼图成功: 耗时%.1f秒,打败了%d%%的用户!", timeUse, penset));

        tipsShowAnime(true);

        flashShowAnime();

        sb.setEnabled(false);

   

    public void fail()

        twinkleImage(ivBlock);

        tvTips.setText("拼图失败: 请重新拖曳滑块到正确的位置!");

        tipsShowAnime(true);

        handler.postDelayed(resetRun, showTipsTime);

        sb.setEnabled(false);

   

    public void reset()

        final int position = sb.getProgress();

        if (position != 0)

            ValueAnimator animator = ValueAnimator.ofFloat(1f, 0);

            animator.setDuration(animeTime).start();

            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()

                @Override

                public void onAnimationUpdate(ValueAnimator animation)

                    float f = (Float) animation.getAnimatedValue();

                    sb.setProgress((int) (position * f));

               

            );

       

        tipsShowAnime(false);

        tips2ShowAnime(true);

        sb.setEnabled(true);

        ivBlock.setVisibility(GONE);

        vFlash.setVisibility(GONE);

        ivCover.setImageBitmap(completeCover);

        isNormal = true;

   

    //===================seekbar监听===================

    private long timeTemp;

    private float timeUse;

    @Override

    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)

        int cw = ivCover.getMeasuredWidth();

        int bw = ivBlock.getMeasuredWidth();

        ViewGroup.MarginLayoutParams l = (MarginLayoutParams) ivBlock.getLayoutParams();

        l.leftMargin = (cw - bw) * progress / seekBar.getMax();

        ivBlock.setLayoutParams(l);

   

    @Override

    public void onStartTrackingTouch(SeekBar seekBar)

        ivBlock.setVisibility(VISIBLE);

        ivCover.setImageBitmap(cover);

        tips2ShowAnime(false);

        timeTemp = System.currentTimeMillis();

        isNormal = false;

   

    @Override

    public void onStopTrackingTouch(SeekBar seekBar)

        timeUse = (System.currentTimeMillis() - timeTemp) / 1000.f;

        if (dragListenner != null)

            dragListenner.onDrag(seekBar.getProgress() * 1f / seekBar.getMax());

   

    //===================seekbar监听===================

    //闪烁滑块

    private void twinkleImage(final View view)

        ValueAnimator animator = ValueAnimator.ofFloat(0, 1.0F);

        animator.setTarget(view);

        animator.setInterpolator(new LinearInterpolator());

        animator.setDuration(showTipsTime).start();

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()

            @Override

            public void onAnimationUpdate(ValueAnimator animation)

                float f = (Float) animation.getAnimatedValue();

                int time = (int) (showTipsTime * f);

                if (time < 125)

                    view.setVisibility(INVISIBLE);

                else if (time < 250)

                    view.setVisibility(VISIBLE);

                else if (time < 375)

                    view.setVisibility(INVISIBLE);

                else

                    view.setVisibility(VISIBLE);

           

        );

   

    //提示文本显示隐藏

    private void tipsShowAnime(boolean isShow)

        if ((tvTips.getVisibility() == VISIBLE) == isShow)

            return;

        TranslateAnimation translateAnimation = new TranslateAnimation(

                Animation.RELATIVE_TO_SELF, 0f,

                Animation.RELATIVE_TO_SELF, 0f,

                Animation.RELATIVE_TO_SELF, isShow ? 1f : 0f,

                Animation.RELATIVE_TO_SELF, isShow ? 0f : 1f);

        translateAnimation.setDuration(animeTime);

        //translateAnimation.setInterpolator(new LinearInterpolator());

        tvTips.setAnimation(translateAnimation);

        tvTips.setVisibility(isShow ? VISIBLE : GONE);

   

    //提示文本显示隐藏

    private void tips2ShowAnime(boolean isShow)

        if ((tvTips2.getVisibility() == VISIBLE) == isShow)

            return;

        AlphaAnimation translateAnimation = new AlphaAnimation(isShow ? 0 : 1, isShow ? 1 : 0);

        translateAnimation.setDuration(animeTime);

        //translateAnimation.setInterpolator(new LinearInterpolator());

        tvTips2.setAnimation(translateAnimation);

        tvTips2.setVisibility(isShow ? VISIBLE : GONE);

   

    //成功完成拼图滑块消失

    private void blockHideAnime()

        AlphaAnimation translateAnimation = new AlphaAnimation(1, 0);

        translateAnimation.setDuration(animeTime);

        //translateAnimation.setInterpolator(new LinearInterpolator());

        ivBlock.setAnimation(translateAnimation);

        ivBlock.setVisibility(GONE);

   

    //失败震动动画

    private void failAnime()

   

    //成功高亮动画

    private void flashShowAnime()

        TranslateAnimation translateAnimation = new TranslateAnimation(

                Animation.RELATIVE_TO_SELF, 1f,

                Animation.RELATIVE_TO_SELF, -1f,

                Animation.RELATIVE_TO_SELF, 0f,

                Animation.RELATIVE_TO_SELF, 0f);

        translateAnimation.setDuration(flashTime);

        //translateAnimation.setInterpolator(new LinearInterpolator());

        vFlash.setAnimation(translateAnimation);

        vFlash.setVisibility(VISIBLE);

        translateAnimation.setAnimationListener(new Animation.AnimationListener()

            @Override

            public void onAnimationStart(Animation animation)

           

            @Override

            public void onAnimationEnd(Animation animation)

                vFlash.setVisibility(GONE);

           

            @Override

            public void onAnimationRepeat(Animation animation)

           

        );

   

    //失败延时重置控件

    private Runnable resetRun = new Runnable()

        @Override

        public void run()

            tipsShowAnime(false);

            tips2ShowAnime(true);

            sb.setEnabled(true);

            final int position = sb.getProgress();

            ValueAnimator animator = ValueAnimator.ofFloat(1f, 0);

            animator.setDuration(animeTime).start();

            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()

                @Override

                public void onAnimationUpdate(ValueAnimator animation)

                    float f = (Float) animation.getAnimatedValue();

                    sb.setProgress((int) (position * f));

               

            );

            isNormal = true;

       

    ;

    //监听

    private DragListenner dragListenner;

    public interface DragListenner

        void onDrag(float position);

   

    public void setDragListenner(DragListenner dragListenner)

        this.dragListenner = dragListenner;

   

js实现滑动拼图验证码

 js实现滑动拼图验证码,我这个样式是仿那些大网站做了, 学习用的,只用到前端。 小的个人网站感觉还可以用,大一点的别人用机器一下就破解了。

下面看图示:

样子大概是这样的。

源码在这 

百度网盘:   链接: https://pan.baidu.com/s/1htjxYBE 密码: m5aw

3.9MB 是因为里面绝大部分是图片

使用示例 代码里面都有

 

js源码

(function (window, document) {
    var SliderBar = function (targetDom, options) {
        // 判断是用函数创建的还是用new创建的。这样我们就可以通过MaskShare("dom") 或 new MaskShare("dom")来使用这个插件了  
        if (!(this instanceof SliderBar)) return new SliderBar(targetDom, options);
        // 参数
        this.options = this.extend({
            dataList: []
        }, options);
        // 获取dom
        this.targetDom = document.getElementById(targetDom);
        var dataList = this.options.dataList;
        if (dataList.length > 0) {
            var html = "<div class=\'slide-box\'><div class=\'slide-img-block\'>" +
                "<div class=\'slide-loading\'></div><div class=\'slide-img-border\'>" +
                "<div class=\'scroll-background slide-top\'></div><div class=\'slide-img-div\'>" +
                "<div class=\'slide-img-nopadding\'><img class=\'slide-img\' id=\'slideImg\' src=\'\' />" +
                "<div class=\'slide-block\' id=\'slideBlock\'></div><div class=\'slide-box-shadow\' id=\'cutBlock\'></div></div>" +
                "<div class=\'scroll-background  slide-img-hint-info\' id=\'slideHintInfo\'>" +
                "<div class=\'slide-img-hint\'><div class=\'scroll-background slide-icon\' id=\'slideIcon\'></div>" +
                "<div class=\'slide-text\'><span class=\'slide-text-type\' id=\'slideType\'></span>" +
                "<span class=\'slide-text-content\' id=\'slideContent\'></span></div></div></div></div>" +
                "<div class=\'scroll-background slide-bottom\'>" +
                "<div class=\'scroll-background slide-bottom-refresh\' id=\'refreshBtn\' title=\'更换图片\'></div>" +
                "<div class=\'slide-bottom-no-logo\'></div></div></div></div>" +
                "<div class=\'scroll-background scroll-bar\'>" +
                "<div class=\'scroll-background slide-btn\' id=\'slideBtn\'></div>" +
                "<div class=\'slide-title\' id=\'slideHint\'> <-按住滑块,拖动完成上面拼图</div></div></div>";
            this.targetDom.innerHTML = html;
            this.slideBtn = document.getElementById("slideBtn");                 // 拖拽按钮
            this.refreshBtn = document.getElementById("refreshBtn");             // 换图按钮
            this.slideHint = document.getElementById("slideHint");               // 提示名称
            this.slideImg = document.getElementById("slideImg");                 // 图片
            this.cutBlock = document.getElementById("cutBlock");                 // 裁剪区域
            this.slideBlock = document.getElementById("slideBlock");             // 裁剪的图片
            this.slideIcon = document.getElementById("slideIcon");               // 正确、失败的图标
            this.slideType = document.getElementById("slideType");               // 正确、失败
            this.slideContent = document.getElementById("slideContent");         // 正确、失败的正文
            this.slideHintInfo = document.getElementById("slideHintInfo");       // 弹出
            this.resultX = 0;
            this.startX = 0;
            this.timer = 0;
            this.startTamp = 0;
            this.endTamp = 0;
            this.x = 0;
            this.imgWidth = 0;
            this.imgHeight = 0;
            this.imgList = [];
            this.isSuccess = true;
            for (var i = 1; i < 10; i++) {
                this.imgList.push(i + ".jpg");
            }
        }
        this.init();
    }
    SliderBar.prototype = {
        init: function () {
            this.event();
        },
        extend: function (obj, obj2) {
            for (var k in obj2) {
                obj[k] = obj2[k];
            }
            return obj;
        },
        event: function () {
            var _this = this;
            _this.reToNewImg();
            _this.slideBtn.onmousedown = function(event){
                _this.mousedown(_this, event);
            } 
            _this.refreshBtn.onclick = function(){
                _this.refreshBtnClick(_this);
            }
        },
        refreshBtnClick: function(_this){
            _this.isSuccess = true;
            _this.slideBlock.style.cssText = "";
            _this.cutBlock.style.cssText = "";
            _this.reToNewImg();
        },
        reToNewImg: function () {
            var _this = this;
            var index = Math.round(Math.random() * 8);         // 该方法有等于0 的情况
            var imgSrc = "./images/" + _this.imgList[index] + "";
            _this.slideImg.setAttribute("src", imgSrc);
            _this.slideBlock.style.backgroundImage = "url("+ imgSrc +")";
            _this.slideImg.onload = function (e) {
                e.stopPropagation();
                _this.imgWidth = _this.slideImg.offsetWidth;                   // 图片宽
                _this.imgHeight = _this.slideImg.offsetHeight;                 // 图片高
            }
        },
        cutImg: function () {
            var _this = this;
            _this.cutBlock.style.display = "block";
            var cutWidth = _this.cutBlock.offsetWidth;                // 裁剪区域宽
            var cutHeight = _this.cutBlock.offsetHeight;              // 裁剪区域高
            // left 
            _this.resultX = Math.floor(Math.random() * (_this.imgWidth - cutWidth * 2 - 4) + cutWidth);
            // top
            var cutTop = Math.floor(Math.random() * (_this.imgHeight - cutHeight * 2) + cutHeight);
            // 设置样式
            _this.cutBlock.style.cssText = "top:" + cutTop + "px;" + "left:" + _this.resultX + "px; display: block;";
            _this.slideBlock.style.top = cutTop + "px";
            _this.slideBlock.style.backgroundPosition = "-" + _this.resultX + "px -" + cutTop + "px";
            _this.slideBlock.style.opacity = "1";
        },
        mousedown: function (_this, e) {
            e.preventDefault();
            _this.startX = e.clientX;
            _this.startTamp = (new Date()).valueOf();
            var target = e.target;
            target.style.backgroundPosition = "0 -216px";
            _this.slideHint.style.opacity = "0";
            if(_this.isSuccess){
                _this.cutImg();
            }
            document.addEventListener(\'mousemove\', mousemove);
            document.addEventListener(\'mouseup\', mouseup);
        
            // 拖拽
            function mousemove(event) {
                _this.x = event.clientX - _this.startX;
                if (_this.x < 0) {
                    _this.slideBtn.style.left = "0px";
                    _this.slideBlock.style.left = "2px";
                } else if (_this.x >= 0 && _this.x <= 217) {
                    _this.slideBtn.style.left = _this.x + "px";
                    _this.slideBlock.style.left = _this.x + "px";
                } else {
                    _this.slideBtn.style.left = "217px";
                    _this.slideBlock.style.left = "217px";
                }
                _this.slideBtn.style.transition = "none";
                _this.slideBlock.style.transition = "none";
            };
            // 鼠标放开
            function mouseup() {
                document.removeEventListener(\'mousemove\', mousemove);
                document.removeEventListener(\'mouseup\', mouseup);
                var left = _this.slideBlock.style.left;
                left = parseInt(left.substring(0, left.length-2));
                if(_this.resultX > (left - 2) && _this.resultX < (left + 2)){
                    _this.isSuccess = true;
                    _this.endTamp = (new Date()).valueOf();
                    _this.timer = ((_this.endTamp - _this.startTamp) / 1000).toFixed(1);
                    // 裁剪图片(拼图的一块)
                    _this.slideBlock.style.opacity = "0";
                    _this.slideBlock.style.transition = "opacity 0.6s";
                    // 裁剪的区域(黑黑的那一块)
                    _this.cutBlock.style.opacity = "0";
                    _this.cutBlock.style.transition = "opacity 0.6s";
                    // 正确弹出的图标
                    _this.slideIcon.style.backgroundPosition = "0 -1207px";
                    _this.slideType.className = "slide-text-type greenColor";
                    _this.slideType.innerHTML = "验证通过:";
                    _this.slideContent.innerHTML = "用时" + _this.timer + "s";
                    setTimeout(function(){
                        _this.cutBlock.style.display = "none";
                        _this.slideBlock.style.left = "2px";
                        _this.reToNewImg();
                    }, 600);
                    _this.options.success&&_this.options.success();
                }else{
                    _this.isSuccess = false;
                    // 设置样式
                    // 裁剪图片(拼图的一块)
                    _this.slideBlock.style.left = "2px";
                    _this.slideBlock.style.transition = "left 0.6s";
                    // 错误弹出的图标
                    _this.slideIcon.style.backgroundPosition = "0 -1229px";
                    _this.slideType.className = "slide-text-type redColor";
                    _this.slideType.innerHTML = "验证失败:";
                    _this.slideContent.innerHTML = "拖动滑块将悬浮图像正确拼合";
                    _this.options.fail&&_this.options.fail();
                }
                // 设置样式
                _this.slideHintInfo.style.height = "22px";
                setTimeout(function(){
                    _this.slideHintInfo.style.height = "0px";
                }, 1300);
                _this.slideBtn.style.backgroundPosition = "0 -84px";
                _this.slideBtn.style.left = "0";
                _this.slideBtn.style.transition = "left 0.6s";
                _this.slideHint.style.opacity = "1";
            }
        }
    }
    window.SliderBar = SliderBar;
}(window, document));

css就不放了

别人的有像拼图一样的凹凸, 那个我实在不知道怎么弄就算了。

 

以上是关于android滑动拼图验证码控件的主要内容,如果未能解决你的问题,请参考以下文章

C# 滑动验证码|拼图验证|SlideCaptcha

js实现滑动拼图验证码

QQ滑块登陆验证码识别的脚本源码

组建验证码的具体工作流程

验证码这样做,瞬间高出一个逼格

几米互联验证码有什用