图片滑动验证Demo
来源:互联网 发布:绝世唐门进阶数据 编辑:程序博客网 时间:2024/06/05 17:20
首先说一下思路,首先绘制一个闭合路径来作为可移动的图片块的形状,在对应的背景图片位置绘制该路径并填充为灰色,接着在新建一个同样大小的图片,背景设为透明,以及一个对应新的Canvas,利用该路径切割Canvas,并绘制背景图片,此时该图片只有路径区域显示背景图片对应位置其他区域为透明,接着重写onDraw(),接着绘制这两张图片,并通过监听move事件移动背景透明的图片。效果如图:
下面是源码:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by lc on 16-12-26.
*/
public class MySlideImage extends View {
private int backgroundId;//验证图片资源ID
private int drawX;//随机生成的x坐标
private int drawY;//随机生成的Y坐标
private boolean backgroundHasDraw = false;//是否时第一次绘制
private int width;//资源图片宽度
private int height;//资源图片高度
private int targetWidth;//图片块宽度
private int targetHeight;//图片块高度
private MoveFinishBack mMoveFinishBack = null;//验证完成后回调接口
private Path mPath;//图片块路径
Bitmap mBitmap;//验证图片
private float lastX = 0;//监听滑动事件上一次坐标
private int targetLength;//可移动图片块所在图片距离左边缘距离,范围为(-drawX,0)
private int moveLength = 12;//底部圆心距离左边缘距离
public MySlideImage(Context context) { super(context);}public MySlideImage(Context context, AttributeSet attrs) { super(context, attrs); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MySlideImage); backgroundId = array.getResourceId(R.styleable.MySlideImage_imageSrc, 0); mBitmap = getBitmapById(backgroundId); width = mBitmap.getWidth(); height = mBitmap.getHeight(); Log.d("lc", "backgroundId = " + backgroundId + "height = " + height + " width = " + width); array.recycle();}/* 创建可移动图块,只有路径所围成的区域可见,其他为透明 */public Bitmap createMoveDrawable() { Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);//创建可移动图片 Canvas canvas = new Canvas(bitmap); canvas.clipPath(getPath());//截取画布,目的只显示需要的图片区域 Paint paint = new Paint(); paint.setAntiAlias(true); if (mBitmap != null) { // canvas.drawBitmap(mBitmap, new Rect(drawX,drawY,drawX+targetWidth,drawY+targetHeight), new RectF(drawX,drawY,drawX+targetWidth,drawY+targetHeight), paint); canvas.drawBitmap(mBitmap, 0, 0, paint); } else { Log.d("lc", "createTargetDrawable :bitmap is null"); } return bitmap;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(width, height + 30);}/* 创建底部背景 */public void createTargetDrawable(Canvas canvas) { Paint paint = new Paint(); paint.setColor(Color.GRAY); paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL_AND_STROKE); if (mBitmap != null) { canvas.drawBitmap(mBitmap, 0, 0, paint); } else { Log.d("lc", "createTargetDrawable :bitmap is null"); } paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); paint.setColor(Color.GREEN); canvas.drawPath(getPath(), paint); backgroundHasDraw = true;}public void getRandomXY() { double random = Math.random(); random = random > (5 * 1.00 / 6) ? (5 * 1.00 / 6) : (random > 1.00 / 6 ? random : 1.00 / 6); Log.d("lc", " random = " + random); drawX = (int) (width * random); drawY = (int) (height * random); Log.d("lc", " drawX = " + drawX + " drawY = " + drawY); targetHeight = height / 6; targetWidth = width / 6; Log.d("lc", " targetHeight = " + targetHeight + " targetWidth = " + targetWidth);}@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setAntiAlias(true); if (!backgroundHasDraw) { getRandomXY(); targetLength = -drawX; moveLength = 12; } drawSeekBar(canvas, paint); createTargetDrawable(canvas); canvas.drawBitmap(createMoveDrawable(), targetLength, 0, paint); drawSeekButton(canvas, paint);}public Bitmap getBitmapById(int resourceId) { return BitmapFactory.decodeResource(getContext().getResources(), resourceId);}public Path getPath() { if (mPath == null) { mPath = new Path(); mPath.moveTo(drawX, drawY); mPath.lineTo(drawX + 10, drawY); mPath.lineTo(drawX + 10, drawY + 15); mPath.lineTo(drawX + targetWidth, drawY + 15); mPath.lineTo(drawX + targetWidth, drawY + targetHeight); mPath.lineTo(drawX, drawY + targetHeight); mPath.lineTo(drawX, drawY); } return mPath;}/* 绘制底部绿色bar */public void drawSeekBar(Canvas canvas, Paint paint) { paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.FILL_AND_STROKE); canvas.drawRoundRect(new RectF(5, height + 10, width - 5, height + 20), 0.5f, 0.5f, paint);}/* 绘制底部红色圆 */public void drawSeekButton(Canvas canvas, Paint paint) { paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL_AND_STROKE); canvas.drawCircle(moveLength, height + 12, 12, paint);}@Overridepublic boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: lastX = event.getX(); Log.d("lc", "action down"); break; case MotionEvent.ACTION_MOVE: float currentX = event.getX(); int length = (int) (currentX - lastX); Log.d("lc", "action move length = " + length); moveLength = Math.max(12, Math.min(width - 12, moveLength + length)); targetLength = Math.max(-drawX, Math.min(width - targetWidth, targetLength + length)); invalidate(); lastX = currentX; break; case MotionEvent.ACTION_UP: boolean finished = false; if (Math.abs(targetLength) < 6) { finished = true; Log.d("lc", " action up " + finished); targetLength = 0; postInvalidateDelayed(300); } else { Log.d("lc", " action up " + finished); moveLength = 12; targetLength = -drawX; postInvalidateDelayed(300); } if (mMoveFinishBack != null) { if (finished) { mMoveFinishBack.MoveFinish(true); } else { mMoveFinishBack.MoveFinish(false); } } break; } return true;}public void setCallBack(MoveFinishBack moveFinishBack) { this.mMoveFinishBack = moveFinishBack;}/* 自定义路径以及设置图片块宽高 */public void setPathAndRect(Path path,int height,int width) { mPath = path; targetWidth = width; targetHeight = height;}/* 刷新图片 */public void refreshImage(){ backgroundHasDraw = false; mPath = null; invalidate();}interface MoveFinishBack { void MoveFinish(boolean correct);}}说明: 1.上面代码中未对图片大小进行判断,所以测试大的图片时需要先对其进行尺寸压缩。 2.图片块的位置采用随机值 3.上例中图片的资源Id是通过自定义属性获得 4.部分手机(图片块只显示为一个矩形)需要在清单文件中关闭硬件加速才能看到完整效果
- 图片滑动验证Demo
- 图片滑动验证码
- 图片滑动验证码js插件
- Python实现图片滑动式验证识别
- 滑动验证
- 可左右滑动 js 图片产品 展示 代码 验证可用
- android 手势滑动demo
- Android 滑动条DEMO
- ViewPager导航滑动Demo
- android滑动菜单demo
- 滑动插件bxSlider-demo
- 实现滑动菜单栏demo
- 图片滑动
- 图片demo
- javascript 滑动验证 仿淘宝滑动验证
- 简单的滑动验证
- Android滑动验证自定义
- jquery 滑动验证码
- 分布式消息系统:Kafka
- Android Studio 出现 Gradle's dependency cache may be corrupt
- Retrofit用法详解
- maven获取远程仓库中的包,下载到本地仓库
- TOSCA简介
- 图片滑动验证Demo
- Fragment的使用分析
- android_14_XmlPullParser解析XML文件
- android 不自动focus EditText
- HttpServletRequestWrapper 实现xss注入
- 23种设计模式(8):观察者模式
- Vitamio
- 43-打通你的任督二脉-信号处理函数的执行期
- Android热修复技术选型——三大流派解析