引导蒙版分为三部分
1、高亮显示的目标布局
2、围绕着目标布局的围栏布局
3、用于提示的蒙版布局
DEMO地址:https://github.com/chaozhouzhang/CustomProgressView
GuideMask guideMask = new GuideMask.Builder(this)
//蒙版所在activity
.setMaskActivity(this)
//目标布局
.setTargetView(mIvTest)
//蒙版背景颜色包括透明度
.setBgColor(Color.parseColor("#40000000"))
//蒙版布局
.setMaskLayout(R.layout.layout_mask)
//关闭蒙版的按钮
.setMaskCloseId(R.id.btn_close)
//围栏与目标布局的距离
.setFencePadding(5,5,5,5)
//围栏布局四角的角度
.setFenceRadius(100)
.build();
GuideMaskSet guideMaskSet = new GuideMaskSet();
//添加蒙版
guideMaskSet.addGuide(guideMask);
//显示所有蒙版
guideMaskSet.show();
在ViewGroup中,初始化时设置了WILL_NOT_DRAW,设置WILL_NOT_DRAW之后,onDraw()不会被调用,目的是略过绘制的过程,优化了性能。所以,在写自定义ViewGroup布局时,如果需要调用onDraw()进行绘制,则需要在初始化时候,调用setWillNotDraw(false)。
setWillNotDraw(false);
配置root为当前自定义布局,配置attachToRoot为true,也就是解析蒙版布局结束后,直接添加到当前自定义布局中。
LayoutInfalter的使用与源码解析可以看本公众号的文章:
LayoutInfalter的使用与源码解析
mMaskLayoutView = LayoutInflater.from(mMaskActivity).inflate(mMaskLayout, this, true);
添加:
mContentParent.post(new Runnable() {
@Override
public void run() {
//显示蒙版,也就是将当前蒙版加到mContentParent的FrameLayout布局上
mContentParent.addView(GuideMask.this, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
});
找到关闭蒙版的ID控件,点击后将自定义布局从activity的content布局中移除:
if (mCloseId != 0) {
//在蒙版布局中找到点击关闭蒙版的控件
mMaskLayoutView.findViewById(mCloseId).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
if (mOnDismissListener != null) {
mOnDismissListener.onDismiss();
}
}
});
}
移除:
public void dismiss() {
mContentParent.post(new Runnable() {
@Override
public void run() {
//关闭蒙版,也就是将当前蒙版从mContentParent的FrameLayout布局上移除
mContentParent.removeView(GuideMask.this);
}
});
}
图像过渡模式,设置为清除模式,用于显示目标布局:
//首先xfermode绘图需要两部分,DST,SRC 两种。可以理解为DST 在下边,SRC在上面。也就是说DST先绘制,SRC 后绘制。
//PorterDuff.Mode.CLEAR:清除模式,[0, 0],即图像中所有像素点的alpha和颜色值均为0。
PorterDuff.Mode mode = PorterDuff.Mode.CLEAR;
mFenceClearMode = new PorterDuffXfermode(mode);
//这个方法用于设置图像的过渡模式,所谓过渡是指图像的饱和度、颜色值等参数的计算结果的图像表现。
//设置围栏区域为清除模式,以达到显示目标布局的目的
mFencePaint.setXfermode(mFenceClearMode);
设置画笔遮罩滤镜,用于凸出目标布局:
//设置画笔遮罩滤镜,传入BlurMaskFilter或EmbossMaskFilter,前者为模糊遮罩滤镜而后者为浮雕遮罩滤镜。
//如果应用启用了硬件加速,将看不到任何阴影效果。
mFencePaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.INNER));
//关闭当前View的硬件加速。
setLayerType(LAYER_TYPE_SOFTWARE, null);
获取目标布局和content布局的位置坐标:
/**
* 获取当前蒙版所目标的布局的坐标位置。
*/
mTargetView.getGlobalVisibleRect(mTargetRect);
/**
* getGlobalVisibleRect()是View可见区域相对与屏幕来说的坐标位置。
* getLocalVisibleRect()是View可见区域想对于自己坐标的位置。
* 获取当前蒙版所在activity根布局的坐标位置。
*/
mContentParent.getGlobalVisibleRect(mContentRect);
计算围栏布局的位置坐标:
/**
* 需要绘制的坐标位置
*/
int topMargin = mContentRect.top;
int left = mTargetRect.left - mPaddingLeft;
mFenceRectF.left = left;
int right = mTargetRect.right + mPaddingRight;
mFenceRectF.right = right;
int top = mTargetRect.top - mPaddingTop - topMargin;
mFenceRectF.top = top;
int bottom = mTargetRect.bottom + mPaddingBottom - topMargin;
mFenceRectF.bottom = bottom;
/**
* rx:x方向上的圆角半径。
* ry:y方向上的圆角半径。
*/
canvas.drawRoundRect(mFenceRectF, mRadius, mRadius, mFencePaint);
GuideMask guideMask = new GuideMask.Builder(this)
//蒙版所在activity
.setMaskActivity(this)
//目标布局
.setTargetView(mIvTest)
//蒙版背景颜色包括透明度
.setBgColor(Color.parseColor("#40000000"))
//蒙版布局
.setMaskLayout(R.layout.layout_mask)
//关闭蒙版的按钮
.setMaskCloseId(R.id.btn_close)
//围栏与目标布局的距离
.setFencePadding(5,5,5,5)
//围栏布局四角的角度
.setFenceRadius(100)
.build();
/**
* 添加蒙版
* @param guideMask
*/
public void addGuide(GuideMask guideMask) {
mGuideMasks.add(guideMask);
guideMask.setOnDismissListener(new GuideMask.OnDismissListener() {
@Override
public void onDismiss() {//关闭后显示下一个蒙版
int nextPosition = mPosition + 1;
if (mGuideMasks.size() > nextPosition) {
GuideMask next = mGuideMasks.get(nextPosition);
mPosition++;
next.show();
}
}
});
}
推荐阅读
你亲手写的代码,正在出卖你
深夜,聊聊架构设计
深夜,分享一个Git小技巧
编程·思维·职场
欢迎扫码关注