前言
满足自定义蒙层颜色,裁剪区域尺寸,自定义说明布局位置,满足自己项目中所需即可,如下图展示:
实现原理
1、浮层的位置在activity的DecorView中,DecorView是FrameLayout的子类,所以整个蒙层,都是基于FrameLayout实现
代码如下:
if (anchor == null) {
anchor = activity.findViewById(android.R.id.content);
}
if (anchor instanceof FrameLayout) {
mParentView = (FrameLayout) anchor;
} else {
FrameLayout frameLayout = new FrameLayout(activity);
ViewGroup parent = (ViewGroup) anchor.getParent();
indexOfChild = parent.indexOfChild(anchor);
parent.removeView(anchor);
if (indexOfChild >= 0) {
parent.addView(frameLayout, indexOfChild, anchor.getLayoutParams());
} else {
parent.addView(frameLayout, anchor.getLayoutParams());
}
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams
(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
frameLayout.addView(anchor, lp);
mParentView = frameLayout;
}
2、高亮区域(待裁剪区域)
(1)、先测绘出需要被裁剪的区域:
@Override
public RectF getRectF(View parent) {
if (view == null) {
throw new IllegalArgumentException("the highlight view is null!");
}
if (rectF == null) {
rectF = new RectF();
Rect locationInView = ViewUtils.getLocationInView(parent, view);
rectF.left = locationInView.left - padding;
rectF.top = locationInView.top - padding;
rectF.right = locationInView.right + padding;
rectF.bottom = locationInView.bottom + padding;
}
return rectF;
}
(2)、通过Paint完成绘制,主要通过setXfeemode实现
代码如下:
mPaint = new Paint();
mPaint.setAntiAlias(true);
PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
mPaint.setXfermode(xfermode);
//设置画笔遮罩滤镜,可以传入BlurMaskFilter或EmbossMaskFilter,前者为模糊遮罩滤镜而后者为浮雕遮罩滤镜
//这个方法已经被标注为过时的方法了,如果你的应用启用了硬件加速,你是看不到任何阴影效果的
mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.INNER));
//关闭当前view的硬件加速
setLayerType(LAYER_TYPE_SOFTWARE, null);
//ViewGroup默认设定为true,会使onDraw方法不执行,如果复写了onDraw(Canvas)方法,需要清除此标记
setWillNotDraw(false);
在onDraw方法中调用:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int backgroundColor = guidePage.getBackgroundColor();
canvas.drawColor(backgroundColor == 0 ? DEFAULT_BACKGROUND_COLOR : backgroundColor);
drawHighlights(canvas);
}
private void drawHighlights(Canvas canvas) {
List<HightLightInterface> highLights = guidePage.getHighLights();
if (highLights != null) {
for (HightLightInterface highLight : highLights) {
RectF rectF = highLight.getRectF((ViewGroup) getParent());
switch (highLight.getShape()) {
case CIRCLE:
canvas.drawCircle(rectF.centerX(), rectF.centerY(), highLight.getRadius(), mPaint);
break;
case OVAL:
canvas.drawOval(rectF, mPaint);
break;
case ROUND_RECTANGLE:
canvas.drawRoundRect(rectF, highLight.getRound(), highLight.getRound(), mPaint);
break;
case RECTANGLE:
default:
canvas.drawRect(rectF, mPaint);
break;
}
}
}
}
3、自定义对高亮区域的说明布局
ps:用注解的方式代替枚举,枚举占用的内存是静态的两倍
@IntDef({Gravity.START, Gravity.TOP, Gravity.END, Gravity.BOTTOM})
@Retention(RetentionPolicy.SOURCE)
@interface LimitGravity {
}
(1)、根据裁剪区域的rectF对说明布局进行位置调整
public View getGuideLayout(ViewGroup viewGroup) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(layout, viewGroup, false);
RectF rectF = highLight.getRectF(viewGroup);
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
switch (gravity) {
case Gravity.START:
layoutParams.leftMargin = 10;
layoutParams.topMargin = (int) (rectF.top + rectF.height() / 2);
layoutParams.rightMargin = (int) (rectF.right + 10);
break;
case Gravity.TOP:
layoutParams.topMargin = (int) (rectF.top / 2);
break;
case Gravity.END:
layoutParams.leftMargin = (int) (rectF.right + 10);
layoutParams.topMargin = (int) (rectF.top + rectF.height() / 2);
layoutParams.rightMargin = 10;
break;
case Gravity.BOTTOM:
layoutParams.topMargin = (int) (rectF.bottom + 100);
break;
}
view.setLayoutParams(layoutParams);
return view;
}
(2)、通过addView的方式添加到FrameLayout中
public void addCustomToLayout(GuidePage guidePage) {
RelativeGuide relativeGuide = guidePage.getRelativeGuide();
addView(relativeGuide.getGuideLayout((ViewGroup) getParent()));
}
Github地址:https://github.com/feifan784/StudyProject.git
PS:guide文件下,可进入首页,点击Guide按钮
总结
站在巨人的肩上看世界,去改变世界!
参考文献:https://www.jianshu.com/p/5aa96683d0dc/