今天实现了利用自定义view实现了一个查看被遮盖的图片功能,不过是通过”偷窥”这种行为实现的,其实这种功能我也不知道怎么命名,就暂且叫他”偷窥”图片,先看下效果吧:
ok,其实该功能和刮刮卡的原理是一样的,只不过刮刮卡对于上层的覆盖层只绘制了一次,所以每次擦除部分是不会恢复的,而对于该实例,上面的图层是每次重绘的时候都会重新绘制的,下实现该功能的原理:
实现思路
- 首先将准备好的图片缩放至和屏幕大小相同
- 在onDraw方法提供的canvas中绘制该图片
- 在onDraw方法提供的canvas中绘制一个和该图片相同大小的bitmap
- 设置当前画笔的xformode=DST_IN,以及颜色透明,这样才可以看到下面这张图片
- 绘制当前的圆形,注意需要设置该圆半径的初始值=0,这样不至于一开始就可以看到底层图片
- 重写onTouchEvent,在用户触摸该view时候,将半径更改到一定的值,并且在手指移动的时候,重新设置当前圆的圆心坐标,在手指抬起的时候,将半径重置为0,重绘,这样就实现了上面的功能。
重写onDraw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//创建一个当前屏幕大小的dstBitmap并根据该dstBitmap创建相同大小的mDstCanvas
mDstBtimap = Bitmap.createBitmap(screenWidth, screenHeight, Config.ARGB_8888);
mDstCanvas = new Canvas(mDstBtimap);
mDstCanvas.drawColor(Color.parseColor("#ccc568"));
//获得mSrcBitmap,并将其缩放至和屏幕大小相同
mSrcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.system);
mSrcBitmap = Bitmap.createScaledBitmap(mSrcBitmap, screenWidth, screenHeight, false);
//先绘制底层的图片,然后绘制相同大小的mDstBtimap使其覆盖底层的图皮
canvas.drawBitmap(mSrcBitmap, 0, 0, null);
canvas.drawBitmap(mDstBtimap, 0, 0,null);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setColor(Color.argb(20,255,0,0));//设置此时的画笔为透明,所以可以看到底层的图片
mDstCanvas.drawCircle(mCurrentX, mCurrentY, mShowCircleRadius, mPaint);
}
这里和我上面描述的原理是一样的,先绘制一个图片,然后绘制一个相同大小的bitmap,遮挡住该图片,设置Paint的模式和透明色,绘制圆。
重写onTouchEvent
@Override
public boolean onTouchEvent(MotionEvent event) {
//每次onTouchEvent方法调用的时候需要重新将手指按下的坐标赋值给圆心坐标,否做会出现当手指抬起后再次按下时候,会在上一个手指抬起时候的坐标显示
//因为mCurrentX 和mCurrentY最后的值就是手指抬起时候的按下的值
mCurrentX = event.getX();
mCurrentY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//当手指按下的时候,将当前圆的半径变为一定的值
mShowCircleRadius += mRadius;
break;
case MotionEvent.ACTION_MOVE:
//获取当前手指按下的坐标,将将其标注为圆心
mCurrentX = event.getX();
mCurrentY = event.getY();
//边界条件判断
mCurrentX = mCurrentX < mRadius ? mRadius : mCurrentX;
mCurrentY = mCurrentY < mRadius ? mRadius : mCurrentY;
mCurrentX = (mCurrentX + mRadius) > screenWidth ? (screenWidth - mRadius) : mCurrentX;
mCurrentY = (mCurrentY + mRadius + getStatusBarHeight()) > screenHeight ? (screenHeight - mRadius - getStatusBarHeight()) : mCurrentY;
Log.d(TAG, "the mCurrentY is :"+mCurrentY+"====the screenHeight is :"+screenHeight+":status bar:"+getStatusBarHeight());
break;
case MotionEvent.ACTION_UP:
mShowCircleRadius = 0;
break;
default:
break;
}
invalidate();
return true;
}
代码注释的比较详细,就不做过多解释了,注意一点,在做边界条件判断的时候,由于最下面的地方需要将手机状态栏的高度考虑进去,因为我们是和整个屏幕的高度来做比较的。
获取状态栏的高度
private int getStatusBarHeight(){
int height=0;
int resouceId=getResources().getIdentifier("status_bar_height", "dimen", "android");
if(resouceId>0){
height=getResources().getDimensionPixelSize(resouceId);
}
return height;
}
可以看到这里我使用资源id首先查找到资源id,然后通过getResources来查看具体的值。
ok,今天的博客就到这里了,希望大家能够喜欢。