0
点赞
收藏
分享

微信扫一扫

android原生滑块验证

记录一个滑块验证,在文章底部会放上DEMO

简单效果图

1、滑动验证前

android原生滑块验证_java

 2、滑动验证后

 android原生滑块验证_滑块_02

用到两个类:

一、自定义类代码

public class ImageAuthenticationView extends android.support.v7.widget.AppCompatImageView {
/**
* 定义画笔
*/
private Paint mPaint;
/**
* 验证的图像
*/
private Bitmap mBitmap;
/**
* 验证滑块的高
*/
private int mUintHeight;
/**
* 验证滑块的宽
*/
private int mUintWidth;
/**
* 验证滑块宽占用整体图片大小的比例,默认1/12
*/
private int mUnitWidthScale;
/**
* 验证滑块高度占用整体图片大小的比例,默认1/10
*/
private int mUnitHeightScale;
/**
* 随机生成滑块的X坐标
*/
private int mUnitRandomX;
/**
* 随机生成滑块的Y坐标
*/
private int mUnitRandomY;
/***
* 滑块移动的距离
*/
private float mUnitMoveDistance = 0;
/***
* 滑块图像
*/
private Bitmap mUnitBp;
/**
* 验证位置图像
*/
private Bitmap mShowBp;
/**
* 背景阴影图像
*/
private Bitmap mShadeBp;
/**
* 是否需要旋转
**/
private boolean needRotate;
/**
* 旋转的角度
*/
private int rotate;
/**
* 判断是否完成的偏差量,默认为10
*/
public int DEFAULT_DEVIATE;
/**
* 判断是否重新绘制图像
*/
private boolean isReSet = true;

/**
* 拼图成功的回调
**/
public interface onPuzzleListener {
public void onSuccess();

public void onFail();
}

/**
* 回调
*/
private onPuzzleListener mlistener;

/**
* 设置回调
*
* @param listener
*/
public void setPuzzleListener(onPuzzleListener listener) {
this.mlistener = listener;
}

public ImageAuthenticationView(Context context) {
this(context, null);
}

public ImageAuthenticationView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public ImageAuthenticationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ImageAuthenticationView);
mUintWidth = ta.getDimensionPixelOffset(R.styleable.ImageAuthenticationView_unitHeight, 0);
mUintHeight = ta.getDimensionPixelOffset(R.styleable.ImageAuthenticationView_unitHeight, 0);
mUnitHeightScale = ta.getInteger(R.styleable.ImageAuthenticationView_unitHeightScale, 10);
mUnitWidthScale = ta.getInteger(R.styleable.ImageAuthenticationView_unitWidthScale, 12);
Drawable showBp = ta.getDrawable(R.styleable.ImageAuthenticationView_unitShowSrc);
mShowBp = drawableToBitamp(showBp);
Drawable shadeBp = ta.getDrawable(R.styleable.ImageAuthenticationView_unitShadeSrc);
mShadeBp = drawableToBitamp(shadeBp);
needRotate = ta.getBoolean(R.styleable.ImageAuthenticationView_needRotate, true);
DEFAULT_DEVIATE = ta.getInteger(R.styleable.ImageAuthenticationView_deviate, 10);
ta.recycle();

//初始化
mPaint = new Paint();
//抗锯齿
mPaint.setAntiAlias(true);
//是否需要旋转
if (needRotate) {
rotate = (int) (Math.random() * 3) * 90;
} else {
rotate = 0;
}
}


/**
* 随机生成生成滑块的XY坐标
*/
private void initUnitXY() {
mUnitRandomX = (int) (Math.random() * (mBitmap.getWidth() - mUintWidth));
mUnitRandomY = (int) (Math.random() * (mBitmap.getHeight() - mUintHeight));
// 防止生成的位置距离太近
if (mUnitRandomX <= mBitmap.getWidth() / 2) {
mUnitRandomX = mUnitRandomX + mBitmap.getWidth() / 4;
}
// 防止生成的X坐标截图时导致异常
if (mUnitRandomX + mUintWidth > getWidth()) {
initUnitXY();
return;
}
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isReSet) {
mBitmap = getBaseBitmap();

if (0 == mUintWidth) {
mUintWidth = mBitmap.getWidth() / mUnitWidthScale;
}

if (0 == mUintHeight) {
mUintHeight = mBitmap.getHeight() / mUnitHeightScale;
}

initUnitXY();
mUnitBp = Bitmap.createBitmap(mBitmap, mUnitRandomX, mUnitRandomY, mUintWidth, mUintHeight);
}
isReSet = false;
canvas.drawBitmap(drawTargetBitmap(), mUnitRandomX, mUnitRandomY, mPaint);
canvas.drawBitmap(drawResultBitmap(mUnitBp), mUnitMoveDistance, mUnitRandomY, mPaint);
}

/**
* 重置
*/
public void reSet() {
isReSet = true;
mUnitMoveDistance = 0;
if (needRotate) {
rotate = (int) (Math.random() * 3) * 90;
} else {
rotate = 0;
}
invalidate();
}

/**
* 获取每次滑动的平均偏移值
*
* @return
*/
public float getAverageDistance(int max) {
return (float) (mBitmap.getWidth() - mUintWidth) / max;
}


/**
* 滑块移动距离
*
* @param distance
*/
public void setUnitMoveDistance(float distance) {
mUnitMoveDistance = distance;
// 防止滑块滑出图片
if (mUnitMoveDistance > mBitmap.getWidth() - mUintWidth) {
mUnitMoveDistance = mBitmap.getWidth() - mUintWidth;
}
invalidate();

}

/**
* 验证是否拼接成功
*/
public void testPuzzle() {
if (Math.abs(mUnitMoveDistance - mUnitRandomX) <= DEFAULT_DEVIATE) {
if (null != mlistener) {
mlistener.onSuccess();
}
} else {
if (null != mlistener) {
mlistener.onFail();
}
}
}

/**
* 创建目标图片(阴影部分)
*
* @return
*/
private Bitmap drawTargetBitmap() {
// 绘制图片
Bitmap showB;
if (null != mShowBp) {
showB = handleBitmap(mShowBp, mUintWidth, mUintHeight);
} else {
showB = handleBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.puzzle_show), mUintWidth, mUintHeight);
}
// 如果需要旋转图片,进行旋转,旋转后为了保持和滑块大小一致,需要重新缩放比例
if (needRotate) {
showB = handleBitmap(rotateBitmap(rotate, showB), mUintWidth, mUintHeight);
}
return showB;
}

/**
* 创建结滑块图片
*
* @param bp
*/
private Bitmap drawResultBitmap(Bitmap bp) {
// 绘制图片
Bitmap shadeB;
if (null != mShadeBp) {
shadeB = handleBitmap(mShadeBp, mUintWidth, mUintHeight);
} else {
shadeB = handleBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.puzzle_shade), mUintWidth, mUintHeight);
}
// 如果需要旋转图片,进行旋转,旋转后为了和画布大小保持一致,避免出现图像显示不全,需要重新缩放比例
if (needRotate) {
shadeB = handleBitmap(rotateBitmap(rotate, shadeB), mUintWidth, mUintHeight);
}
Bitmap resultBmp = Bitmap.createBitmap(mUintWidth, mUintHeight,
Bitmap.Config.ARGB_8888);
Paint paint = new Paint();
paint.setAntiAlias(true);
Canvas canvas = new Canvas(resultBmp);
canvas.drawBitmap(shadeB, new Rect(0, 0, mUintWidth, mUintHeight),
new Rect(0, 0, mUintWidth, mUintHeight), paint);
// 选择交集去上层图片
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
canvas.drawBitmap(bp, new Rect(0, 0, mUintWidth, mUintHeight),
new Rect(0, 0, mUintWidth, mUintHeight), paint);
return resultBmp;
}

/**
* 获取实际显示的图片
*
* @return
*/
public Bitmap getBaseBitmap() {
//获取背景图片Bitmap
Bitmap b = drawableToBitamp(getDrawable());
float scaleX = 1.0f;
float scaleY = 1.0f;
// 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值;
scaleX = getWidth() * 1.0f / b.getWidth();
scaleY = getHeight() * 1.0f / b.getHeight();
//按比例缩放
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY);
Bitmap bd = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
matrix, true);
return bd;
}

/**
* drawable转bitmap
*
* @param drawable
* @return
*/
private Bitmap drawableToBitamp(Drawable drawable) {
if (null == drawable) {
return null;
}

if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();//该方法用于BitmapDrawable转换成Bitmap
}

//获取drawable的宽高
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
//创建Bitmap后无法进行修改
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
//创建对应的Bitmap画布
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}

/**
* 缩放图片
*
* @param bp
* @param x
* @param y
* @return
*/
public static Bitmap handleBitmap(Bitmap bp, float x, float y) {
int w = bp.getWidth();
int h = bp.getHeight();
float sx = (float) x / w;
float sy = (float) y / h;
Matrix matrix = new Matrix();
matrix.postScale(sx, sy);
Bitmap resizeBmp = Bitmap.createBitmap(bp, 0, 0, w,
h, matrix, true);
return resizeBmp;
}

/**
* 旋转图片
*
* @param degree
* @param bitmap
* @return
*/
public Bitmap rotateBitmap(int degree, Bitmap bitmap) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
return bm;
}
}

具体说明代码中已经有说明。

二、主类引用监听结果代码

public class MainActivity extends Activity {

//滑块
private SeekBar mSeekBar;
//自定义的控件
private ImageAuthenticationView mDY;
private Button btn;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
}

private void initView() {
mDY = findViewById(R.id.dy_v);
mSeekBar = findViewById(R.id.sb_dy);
btn = findViewById(R.id.btn);
}

private void initListener() {
//滑块监听
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
//设置滑块移动距离
mDY.setUnitMoveDistance(mDY.getAverageDistance(seekBar.getMax()) * i);
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {

}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//验证是否拼接成功
mDY.testPuzzle();
}
});

//控件监听
mDY.setPuzzleListener(new ImageAuthenticationView.onPuzzleListener() {
@Override
public void onSuccess() {
//mSeekBar.setEnabled(false);//禁止滑动
Toast.makeText(MainActivity.this, "验证成功", Toast.LENGTH_SHORT).show();
}

@Override
public void onFail() {
Toast.makeText(MainActivity.this, "验证失败", Toast.LENGTH_SHORT).show();
mSeekBar.setProgress(0);
}
});

//还原
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//mSeekBar.setEnabled(true);
mSeekBar.setProgress(0);
mDY.reSet();
}
});
}

三、XML文件代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dy="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingRight="10dp"
android:paddingBottom="10dp"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="50sp"
android:textSize="40sp"
android:text="模块滑动验证demo"
/>

<com.sjl.keeplive.slideImg.ImageAuthenticationView
android:id="@+id/dy_v"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:layout_marginBottom="10dp"
android:src="@mipmap/grls"
dy:needRotate="true"
dy:unitHeight="60dp"
dy:unitShadeSrc="@mipmap/puzzle_shade"
dy:unitShowSrc="@mipmap/puzzle_show"
dy:unitWidth="80dp" />

<SeekBar
android:id="@+id/sb_dy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_seekbar"
android:max="150" />

<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="还原"/>
</LinearLayout>

滑动模块全部代码,具体效果可以下载demo

                                                                                             -END


举报

相关推荐

0 条评论