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滑动拼图验证码控件的主要内容,如果未能解决你的问题,请参考以下文章