一、说在前面的话

我们在做新手引导时,经常会遇到凸显某一块功能时需求,类似于下图:

看到这个功能点可能会有点头大,不过好在Android为我们提供一个美好的工具:PorterDuffXfermode
至于它的功能介绍和简单使用,大家可以参考这篇文章

今天我们就用到其中一个模式:DST_OUT,它的解释:只在源图像和目标图像不相交的地方绘制【目标图像】,在相交的地方根据源图像的alpha进行过滤,源图像完全不透明则完全过滤,完全透明则不过滤

至于怎么使用它呢,下面开始吧
1、我们需要把镂空的Bitmap给绘制出来和灰色的背景进行叠加绘制。也可以把从View中获取Bitmap:

    public static Bitmap buildViewDrawCache(View target, @ColorInt int color) {Bitmap bitmap = null;if (target == null) {return null;}try {target.destroyDrawingCache();target.setDrawingCacheBackgroundColor(color);boolean isEnable = target.isDrawingCacheEnabled();if (!isEnable) {target.setDrawingCacheEnabled(true);}bitmap = target.getDrawingCache();} catch (Throwable error) {}return bitmap;}

具体绘制:

 @Overridepublic void draw(Canvas canvas) {super.draw(canvas);int layoutId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);//绘制背景canvas.drawColor(mBackgroundColor);//绘制需要镂空的图形canvas.drawBitmap(bitmap, null, hollowingInfo.rectF, mPaint);canvas.restoreToCount(layoutId);

2、设置使用PorterDuffXfermode的模式

public class HomeBgGuideView extends View {private int mBackgroundColor;private PorterDuffXfermode mBitmapfermode;private Paint mPaint;public HomeBgGuideView(Context context) {super(context);initLayout();}public HomeBgGuideView(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);initLayout();}private void initLayout() {if (DEBUG) {Log.d(TAG, "initLayout() called");}Resources resources = getResources();mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mBackgroundColor = resources.getColor(R.color.black_alpha_80);mBitmapfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);}@Overridepublic void draw(Canvas canvas) {super.draw(canvas);int layoutId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);canvas.drawColor(mBackgroundColor);//设置镂空的模式mPaint.setXfermode(mBitmapfermode);canvas.drawBitmap(bitmap, null, rectF, mPaint);//清空镂空模式mPaint.setXfermode(null);canvas.restoreToCount(layoutId);}...
}

3、确定图形镂空的定位,我们可以通过getLocationOnScreen方法获取当前需要镂空View的位置

 int[] location = new int[2];anchorView.getLocationOnScreen(location);float x = location[0];float y = location[1];mAnchorRect.set(x, y, x + anchorView.getWidth() * 2, y + anchorView.getHeight() * 2);

至此 整个不规则镂空的使用方式介绍完毕

完成代码如下:

public class HomeBgGuideView extends View {private static final boolean DEBUG = BuildConfig.DEBUG;private static final String TAG = DEBUG ? "BarracksGuideView" : "";private int mBackgroundColor;private PorterDuffXfermode mXfermode;private PorterDuffXfermode mBitmapfermode;private Paint mPaint;//镂空的集合private List<HollowingInfo> mHollowingOutList = new ArrayList<>();private float mRadius;public HomeBgGuideView(Context context) {super(context);initLayout();}public HomeBgGuideView(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);initLayout();}private void initLayout() {if (DEBUG) {Log.d(TAG, "initLayout() called");}Resources resources = getResources();mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mBackgroundColor = resources.getColor(R.color.black_alpha_80);mXfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);mBitmapfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);mRadius = getResources().getDimension(R.dimen.dp_10);}@Overridepublic void draw(Canvas canvas) {super.draw(canvas);int layoutId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);canvas.drawColor(mBackgroundColor);//判断镂空集合不为空时,则进行镂空处理if (mHollowingOutList != null) {//遍历集合for (HollowingInfo hollowingInfo : mHollowingOutList) {//判断如果为图形类型if (hollowingInfo.hollowingState == HollowingState.SHAPE) {mPaint.setXfermode(mXfermode);float radius = hollowingInfo.mRadius == 0 ? mRadius : hollowingInfo.mRadius;canvas.drawRoundRect(hollowingInfo.rectF, radius, radius, mPaint);}//判断如果为图片类型时,则进行镂空处理else if (hollowingInfo.bitmap != null && hollowingInfo.bitmap.get() != null &&hollowingInfo.hollowingState == HollowingState.BITMAP) {mPaint.setXfermode(mBitmapfermode);canvas.drawBitmap(hollowingInfo.bitmap.get(), null, hollowingInfo.rectF, mPaint);}}}mPaint.setXfermode(null);canvas.restoreToCount(layoutId);}/*** 设置圆角*/public void setRadius(float radius) {if (DEBUG) {Log.d(TAG, "setRadius() called with: radius = [" + radius + "]");}mRadius = radius;postInvalidate();}/*** 设置数据集合*/public void setShapeDataList(List<RectF> rectList) {if (DEBUG) {Log.d(TAG, "setDataList() called with: rectList = [" + rectList + "]");}if (rectList == null || rectList.isEmpty()) {return;}List<HollowingInfo> dataList = new ArrayList<>(rectList.size());for (RectF rectF : rectList) {HollowingInfo hollowingInfo = new HollowingInfo();hollowingInfo.rectF = rectF;dataList.add(hollowingInfo);}setDataList(dataList);}/*** 设置数据集合*/public void setDataList(List<HollowingInfo> rectList) {if (DEBUG) {Log.d(TAG, "setDataList() called with: rectList = [" + rectList + "]");}if (rectList == null || rectList.isEmpty()) {return;}mHollowingOutList.clear();mHollowingOutList.addAll(rectList);postInvalidate();}/*** 清除数据*/public void clearHollowingOutList() {if (mHollowingOutList == null) {return;}for (HollowingInfo hollowingInfo : mHollowingOutList) {hollowingInfo.rectF = null;if (hollowingInfo.bitmap != null) {hollowingInfo.bitmap.clear();hollowingInfo.bitmap = null;}}mHollowingOutList.clear();postInvalidate();}public static class HollowingInfo {public RectF rectF;public float mRadius;public SoftReference<Bitmap> bitmap;public HollowingState hollowingState = HollowingState.SHAPE;}public enum HollowingState {BITMAP, SHAPE}}

在这里大家可以有一个疑问,为什么绘制镂空的不规则图形时使用的是DST_OUT,而使用绘制规则图形时使用CLEAR, 大家可以评论区讨论

Android中图片的镂空效果(不规则图形的镂空)相关推荐

  1. android怎么用代码调图像,浅谈android中图片处理之图形变换特效Matrix(四)(示例代码)...

    今天,我们就来谈下android中图片的变形的特效,在上讲博客中我们谈到android中图片中的色彩特效来实现的.改变它的颜色主要通过ColorMatrix类来实现. 现在今天所讲的图片变形的特效主要 ...

  2. 浅谈android中图片处理之图形变换特效Matrix(四)

    今天,我们就来谈下android中图片的变形的特效,在上讲博客中我们谈到android中图片中的色彩特效来实现的.改变它的颜色主要通过ColorMatrix类来实现. 现在今天所讲的图片变形的特效主要 ...

  3. Android中RatingBar的自定义效果

    Android中RatingBar的自定义效果 有时候android系统提供给我们的ratingbar效果并不达到我们的要求,这个时候就可以自定义自己喜欢的ratingbar. 从上面的效果可以看出, ...

  4. android图片分割点击,Android中图片切割成多个图片的实现方法

    系统手机总是有很多不是很完美的时候,比如逐帧播放图片的时候产生的效果,今天爱站技术频道小编为大家整理了Android中图片切割成多个图片的实现方法,大家一起来了解一下吧! 以下是封装好的两个类,可以实 ...

  5. android中设置Animation 动画效果

    在 Android 中, Animation 动画效果的实现可以通过两种方式进行实现,一种是 tweened animation 渐变动画,另一种是 frame by frame animation ...

  6. Android 系统(173)---Android中图片的三级缓存

    Android中图片的三级缓存 为什么要使用三级缓存 如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了 假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量 ...

  7. 微信小程序手把手教你实现类似Android中ViewPager控件效果

    微信小程序手把手教你实现类似Android中ViewPager控件效果 前言 需求分析 头部TAB 滑动的内容部分 最终版本 尾巴 前言 在做Android开发的时候,ViewPager是开发者使用频 ...

  8. android 不压缩保存图片格式,Android中图片的压缩方法

    Bitmap Android中图片是以Bitmap(位图)形式存在,位图常见的文件格式有:.bmp .jpg .png .gif . Bitmap的大小计算 = 图片的长度图片的宽度单位像素所占用的字 ...

  9. android中图片适配器,Android UI适配总结之图片适配(1)

    由于Android的屏幕尺寸的碎片化,时至今日Android的UI适配依然是开发中必不可少的步骤. UI适配的适配,是通过dp.权重,通配符等方式使View能按我们意愿的准确的显示在不同手机上.除了对 ...

最新文章

  1. SQL Server创建视图——视图的作用
  2. redis 用setbit(bitmap)统计活跃用户
  3. requests库详解
  4. PHP使用session_set_save_handler陷阱
  5. 蓝桥杯基础模块9:IO口扩展与存储器映射
  6. XGBoost入门及实战
  7. CEF编译遇到的问题记录
  8. HashMap的底层原理 cr:csdn:zhangshixi
  9. 太阳粒子是什么东西_太阳粒子流是什么
  10. [SoftWare]基于Windriver快速驱动开发
  11. Python贝叶斯决策面计算及仿真
  12. 《BPF( 伯克利数据包过滤器 ) Performance Tools》 第二章 技术背景
  13. Canvas基础教程
  14. 史上最详细:word文档怎么在第三页插入页码,只要7步
  15. 树莓派改造成通用计算机,自制树莓派笔记本电脑,你也可以做到
  16. stm32f103 时钟系统
  17. 从GitHub上下载项目后如何运行,学习
  18. 《密码朋克:自由与互联网的未来》[澳] 朱利安-阿桑奇
  19. jdk,neo4j社区版本下载与安装
  20. 卖头上草记---记人生迟到的第一桶金

热门文章

  1. ScriptManager导致ASP.NET Ajax 客户端框架未能加载。Uncaught ReferenceError: Type is not defined
  2. v9手机版文章内容不显示
  3. 用批处理来设置文件夹权限
  4. 淘宝网的质量属性分析
  5. 安全加固之Windows安全加固
  6. 【蓝桥杯】16转换8进制
  7. 国内中文域名交易前景如何?
  8. 百度地图开发(8):地图覆盖物实现纵横交错的交通网络
  9. 网站的SEO外链你需要怎么发
  10. Android 仿qq上传头像(一)