分析需求
高亮显示指定的控件(1个或者多个)只有一个高亮控件,则直接绘制即可
多个高亮控件,则分两种效果展示顺序展示每一个控件
展示所有控件
高亮部分的形状方形
圆形
展示与消失自动展示,自动消失
点击消失
点击指定部分消失
实现方式
遮罩层直接在本来的页面是添加,不用时消失
使用DecorView的方式,添加view即可
使用透明Activity覆盖
选择第二种方式来实现
第一种方便但是耗时耗力,并且不能通用
第二种是大家都认可的一种方式,而且支持配置
第三种,对原界面生命周期造成影响,不太好
高亮的实现
PorterDuffXfermode :: PorterDuff.Mode.XOR)
代码设计mask layer View 用来实现遮罩层高亮显示绘制
指示语位置
mask layer Manager 用来管理 遮罩层addView
Show / hide
DecorView 操作
其他配置信息
mask bean 用来存放需要高亮的View信息(高度,宽度..)
实现
mask:
MaskGuideView 遮罩层容器
MaskLayout 高亮控件与指示语的位置,以及排列展示
MaskManager 加载管理整个遮罩层
MaskType 高亮控件的形状, 圆 方
TargetInfo 高亮控件的位置信息
TargetInfo.java/**
* If you have any questions, you can contact by email { [email protected]}
*
* @author 王诛魔 2018/5/21 下午7:20
*
* 高亮区域信息
*/
public class TargetInfo {
/*
* 高亮区域起始X坐标
*/
public int startX;
/*
* 高亮区域起始Y坐标
*/
public int startY;
/*
* 高亮区域宽度
*/
public int width;
/*
* 高亮区域高度
*/
public int height;
/*
* 偏移量
*/
public int offset = 10;
/**
* 获取半径
*/
public int getRadius() {
return Math.max(width, height) / 2;
}
}
MaskType.java/**
* If you have any questions, you can contact by email { [email protected]}
*
* @author 王诛魔 2018/5/21 下午7:18
*/
public enum MaskType {
Rect,Circle
}/**
* If you have any questions, you can contact by email { [email protected]}
*
* @author 王诛魔 2018/5/21 下午11:35
*
* 负责管理,准备,操作MaskGuideView
*/
public class MaskManager {
//属性
private static final String TAG = "MaskManager";
private final ViewGroup mRootView;
private final MaskGuideView mMaskGuideView;
private final Context mContext;
private List mTargetInfoList;
private List mTargetViewList;
private List mMaskLayoutList;
private MaskType mMaskType;
private boolean isShowAll;
private int mPadding;
/**
* 计算targetInfo
*
* @param targetView view
* @return TargetInfo
*/
private TargetInfo generateTargetInfo(View targetView) {
int[] location = new int[2];
//我们需要的是,这个targetView在整个屏幕上的位置
targetView.getLocationOnScreen(location);
TargetInfo targetInfo = new TargetInfo();
//计算startX width ...
switch (mMaskType) {
case Rect:
targetInfo.startX = location[0] - mPadding;
targetInfo.startY = location[1] - mPadding;
targetInfo.width = targetView.getWidth() + 2 * mPadding;
targetInfo.height = targetView.getHeight() + 2 * mPadding;
break;
case Circle:
int diameter = Math.max(targetView.getWidth() + 2 * mPadding, targetView.getHeight() + 2 * mPadding);
targetInfo.startX = location[0] - mPadding;
targetInfo.startY = location[1] - mPadding - (diameter / 2 - targetView.getHeight() / 2 - mPadding);
targetInfo.width = diameter;
targetInfo.height = diameter;
break;
}
Log.e(TAG, "generateTargetInfo: " + targetInfo.toString() );
return targetInfo;
}
/*
* builder模式
*/
public static class Builder {
private ViewGroup mRootView;
private MaskGuideView mMaskGuideView;
private Context mContext;
private List mTargetInfoList;
private List mMaskLayoutList;
private List mTargetViewList;
private MaskType mMaskType = MaskType.Circle;
private int mPadding = 0;
private int mGravity = Gravity.TOP;
private boolean isShowAll;
...省略
public MaskManager build() {
this.mMaskGuideView.setOnClickListener(this.mMaskGuideView);
return new MaskManager(this);
}
}
}
额,代码传git好了