遮罩层实现思路

效果图

遮罩层效果图
遮罩层效果为: 除目标区域透明度为全透明,其余部分为50%透明黑,造成一种目标区域高亮效果

思考

关于遮罩层的实现,通常是直接制作成png格式的图进行覆盖,但是会产生以下几个问题

  1. 定位不准确
  2. 适配困难,不同分辨率手机的对应位置不同,适配手机需要制作多个遮罩层图片
  3. 有N个遮罩层,就需要加入N张遮罩层png图片,大大提高安装包体积

由此,考虑是否可以通过自定义View的形式,画出遮罩层,一个View覆盖多场景

自定义MaskView

首先分析遮罩层结构

  • 挖孔大背景
  • 目标区域

细分结构之后可以这样划分

  • 目标区域形状Path
  • 剔除Path之后进行上色

Path路径

path路径可以随意定义,此处构造了一个圆心在(x, y)位置的半径为radius的圆形路径,最后一个参数为顺/逆时针,不做特别要求

Path path = new Path();
path.addCircle(x, y, radius, Path.Direction.CCW);

除path区域外显示半透明

切割画布,并进行上色

// 切割画布方法,后一个参数表示切除canvas上与path相交区域
 canvas.clipPath(path, Region.Op.DIFFERENCE);
// 切割后进行上色
 canvas.drawColor(getResources().getColor(R.color.half_alpha_black));

实现代码

MaskView.java
// 初始化代码
private void init(){
    // 设置路径
    path.addCircle(x, y, radius, Path.Direction.CCW);
    // 画笔使用白色
    paint.setColor(Color.WHITE);
    // 绘制线条,不封闭区域,否则导致整个圆上色
    paint.setStyle(Paint.Style.STROKE);
    // 抗锯齿
    paint.setAntiAlias(true);
    // 虚线,第一个参数实线宽度,第二个参数间隔宽度
    paint.setPathEffect(new DashPathEffect(new float[] {10, 20}, 1));
    // 线段宽度
    paint.setStrokeWidth(2f);
    // 圆角线
    paint.setStrokeCap(Paint.Cap.ROUND);
}

// 绘制
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (path.isEmpty()){
        // path无路径时清空画布
        canvas.drawColor(Color.TRANSPARENT);
    } else {
        // 做切割并上色时,需要先保存状态,上色后进行还原,否则导致后续绘制路径时无法绘制
        canvas.save();
        // 先切割后上色
        canvas.clipPath(path, Region.Op.DIFFERENCE);
        canvas.drawColor(getResources().getColor(R.color.half_alpha_black));
        canvas.restore();
        // 最后绘制路径,显示在最上层
        canvas.drawPath(path, paint);
    }
}

获取位置

前面的view代码还是最基础的部分,因为path关键参数path的x,y,radius还不知道
要想获取到定位,首先是要获取到对应的View对象,再进行测量
测量有3种方式,测量的首要前提是,view已经绘制完毕

1. view.getLocationInWindow(int[] l)

该方法获取该View在window中的位置,剔除了状态栏的高度
其中int[] l为数组,数组size需要大于等于2
l[0] 为view左上角相对window左上角的x值
l[1] 为view左上角相对window左上角的y值

2. view.getLocationOnScreen(int[] l)

该方法获取该View在屏幕中的位置
其中int[] l为数组,数组size需要大于等于2
l[0] 为view左上角相对屏幕左上角的x值
l[1] 为view左上角相对屏幕左上角的y值

3. view.getGlobalVisibleRect(Rect rect)

该方法获取该View在屏幕中的Rect测量值,rect为矩形,其中的属性:
left为view中的最左边的x值,right为view中最右边的x值,top为view中最上面的y值,bottom为view中最下面的y值
如果想要绘制,譬如图中的圆形,并且在对应view上居中,使用该方法更为方便

Last modification:August 29th, 2019 at 04:26 pm
如果觉得我的文章对你有用,请我喝杯咖啡

Leave a Comment