Android 自定义 高亮 新手引导页
·
今天打算跟大家分享一个 用于首次安装 ,用户功能引导页。可能现在有些开源的高亮引导控件无法满足设计的需求,那么大家可以看一看我这篇文章,并不是十分的完善,仅仅是为了给大家提供一个思路,那么下面我写一下实现的思路。
一,拿到当前activity的decorview 我们的蒙层是加到这个decorview 中 。我们知道每一个activity的页面实际上都是在decorview 中的。而decorview 又是一个framelayout 所以我们的高亮蒙层 放到decorview 中就可以实现遮罩层的效果。
二,在绘制时根据获取到的decorview 设置你的自定义view的尺寸 。这样保证完全覆盖你的activity。不会有尺寸适配的问题。
三,构建一个画笔 ,并设置它的xfermode 为 clear, 这个画笔 用于在你的自定义view 上抠一块透明的区域出来 。
四,根据传入的目标view 计算它在当前屏幕中的坐标。根据它的坐标计算它的中点坐标,然后构建一个高亮区域的矩形rect 用于绘制高亮区域。当然要结合上一步的画笔
五,根据设计图 ,计算指引文字在高亮区域的相对位置。计算一个坐标。用于绘制指引文字或者图片。
六 ,根据需求计算一个用于点击区域的 rect ,当用户触摸时 计算触摸位置如果是符合要求的那么 可以进行隐藏蒙层或者进行其他操作
基本主要实现思路就是上面的六步,然后我会将实现的代码贴在下面 ,我已经将每一步的代码都做了相应的注释。大家如果想看可以按照注释来对照我上面写的思路,来最终设计你们自己的自定义view 来实现你们的需求。
public class GuideViewTest extends View {
Paint bgPaint, highLightP;
Bitmap bgBitmap;
Canvas bgCanvas;
private int mWidth;
private int mHeight;
private FrameLayout decorFrameLayout;
private int highW;
private int highH;
int[] hvLocation=new int[2];
Rect centerBtnRec =new Rect();
int centerBtnW=DensityUtil.dip2px(88);
int centerBtnH=DensityUtil.dip2px(34);
private View highView; //高亮提示view
float originx = 0;
float originy=0 ;
float dtx=0;
float dty=0;
private int highCornerSize=DensityUtil.dip2px(5);
public GuideViewTest(Context context) {
this(context,null);
}
public GuideViewTest(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public GuideViewTest(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
bgPaint = new Paint();
bgPaint.setAntiAlias(true);
setLayerType(LAYER_TYPE_HARDWARE, null);
if(mContext instanceof Activity){
Activity activity = (Activity) mContext;
//1 . 通过activity 对象获得根布局decorview
final View decorView = activity.getWindow().getDecorView();
if(decorView instanceof FrameLayout){
decorFrameLayout = (FrameLayout) decorView;
final ViewTreeObserver vto =decorFrameLayout.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
decorFrameLayout.getViewTreeObserver().removeOnPreDrawListener(this);
//2 . 通过decorview 获取整体屏幕的宽高
mHeight=decorFrameLayout.getHeight();
mWidth=decorFrameLayout.getWidth();
centerBtnRec.left=mWidth/2-centerBtnW/2;
centerBtnRec.right=mWidth/2+centerBtnW/2;
centerBtnRec.top=mHeight/2-centerBtnH/2;
centerBtnRec.bottom=mHeight/2+centerBtnH/2;
if(mWidth>0&&mHeight>0){
//3 . 设置蒙层与屏幕的宽高相等
setMeasuredDimension( MeasureSpec.makeMeasureSpec(mWidth,MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mHeight,MeasureSpec.EXACTLY));
//4 . 创建一个 用于绘制指引 文字的背景画布 宽高与 蒙层相同
bgBitmap = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
bgCanvas = new Canvas(bgBitmap);
}
return true;
}
});
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//设置 半透明 背景色
setBackgroundColor(Color.argb((int) (255*0.4f),0,0,0));
if(bgCanvas !=null){
checkParams();
//创建 高亮画笔
highLightP = new Paint();
highLightP.setColor(Color.YELLOW);
highLightP.setAntiAlias(true);
//5 .每次绘制前清除背景画布
clearCanvas(bgCanvas);
// 根据传入的 高亮目标view 计算它 在屏幕中的坐标
highView.getLocationInWindow(hvLocation);
hvLocation[0]=hvLocation[0]+highView.getWidth()/2;
hvLocation[1]=hvLocation[1]+highView.getHeight()/2;
// 根据目标view 的坐标以他的中心为中心点 扩大范围 计算出一个 矩形范围 作为高亮显示区域
RectF rectF = new RectF(hvLocation[0] - highW / 2, hvLocation[1] - highH / 2
, hvLocation[0] + highW / 2, hvLocation[1] + highH / 2);
canvasGuideUI();
// 8 .设置高亮 画笔 的 mode 为clear 这样可以在背景上 抠出一片 透明区域
highLightP.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
// 9 . 将高亮区域 矩形绘制到 画布上 。
canvas.drawRoundRect(rectF,highCornerSize,highCornerSize,highLightP);
// 10 ,将 创建的 背景画布 绘制到画布上 。
canvas.drawBitmap(bgBitmap,0,0, bgPaint);
}
}
/**
* 根据页面类型计算坐标
*/
private void canvasGuideUI() {
float left;
float top ;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.文字);
int bmpwidth = bitmap.getWidth();
//6 .根据实际ui的效果图计算一下 文字与高亮显示区域的坐标即可
top=hvLocation[1]+1/3*highH-bitmap.getHeight();
left= hvLocation[0]-highW/2-bmpwidth*(4f/5);
float bottom = top+bitmap.getHeight();
Paint bmp=new Paint(Paint.ANTI_ALIAS_FLAG);
//7 .将提示文字绘制到 背景画布上
bgCanvas.drawBitmap(BitmapFactory.decodeResource(mContext.
getResources(),R.drawable.文字),centerBtnRec.left,centerBtnRec.top,bmp);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int defClickSize=20;
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
originx=event.getX();
originy=event.getY();
// LogUtil.i(TAG,originx+"+++"+originy);
break;
case MotionEvent.ACTION_UP:
dtx=event.getX()-originx;
dty=event.getY()-originy;
//如果触摸和抬起的 x y 坐标偏移量不至于过高那么 认为是点击操作
if(Math.abs(dtx)<defClickSize&&Math.abs(dty)<defClickSize){
//如果触摸位置在我规定的 点击位置内 处理点击事件
if(centerBtnRec.contains((int)event.getX(),(int)event.getY())){
//处理点击事件
dismiss();
}
}
// LogUtil.i(TAG,event.getX()+"=="+(event.getX()-originx));
break;
}
return true;
}
private void checkParams() {
if(highView==null){
return ;
}
if(highW<=0||highW<=0){
return ;
}
}
/**
* 默认矩形高亮
* 设置高亮部分的宽高
* 传入dp 值
*/
public GuideViewTest setHighlightSize(int highW,int highH){
this.highW= DensityUtil.dip2px(highW);
this.highH= DensityUtil.dip2px(highH);
return this;
}
/**
* 需要高亮提示的View
* @param view
*/
public GuideViewTest setHighView(View view){
highView=view;
return this;
}
/**
* 显示guideview
*/
public void show(){
FrameLayout.LayoutParams f=new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
if(decorFrameLayout!=null)
decorFrameLayout.addView(GuideViewTest.this,f);
invalidate();
}
/**
* 隐藏guideview
*/
public void dismiss(){
if(decorFrameLayout!=null){
decorFrameLayout.removeView(this);
}
bgCanvas=null;
bgPaint=null;
highLightP=null;
if(bgBitmap!=null)
bgBitmap.recycle();
bgBitmap=null;
}
}
更多推荐
已为社区贡献2条内容
所有评论(0)