package com.zhl.userguideview; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.support.v4.content.ContextCompat; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; import java.util.ArrayList; /** * * des:“应用新功能”的用户指引view * Created by jaydenxiao * on 2016.08.11:59 */ public class HighLightGuideView extends View { //高亮类型:矩形、圆形、椭圆形 public static final int VIEWSTYLE_RECT = 0; public static final int VIEWSTYLE_CIRCLE = 1; public static final int VIEWSTYLE_OVAL = 2; //画笔类型,圆滑、默认 public static final int MASKBLURSTYLE_SOLID = 0; public static final int MASKBLURSTYLE_NORMAL = 1; private View rootView;//activity的contentview,是FrameLayout private Bitmap jtUpLeft, jtUpRight, jtDownRight, jtDownLeft;// 指示箭头 private Bitmap fgBitmap;// 前景 private Canvas mCanvas;// 绘制蒙版层的画布 private Paint mPaint;// 绘制蒙版层画笔 private int screenW, screenH;// 屏幕宽高 private static final int margin = 40; private int radius;//圆半径 private OnDismissListener onDismissListener;//关闭监听 private Activity activity; /*******************可配置属性*****************************/ private boolean touchOutsideCancel = true;//外部点击是否可关闭 private int highLightStyle = VIEWSTYLE_RECT;//高亮类型默认圆形 public int maskblurstyle = MASKBLURSTYLE_SOLID;//画笔类型默认 private ArrayList<Bitmap> tipBitmaps;//显示图片 private ArrayList<View> targetViews;//高亮目标view private int maskColor = 0x99000000;// 蒙版层颜色 private int borderWitdh = 10; private int highLisghtPadding = 0;// 高亮控件padding private HighLightGuideView(Activity activity) { super(activity); this.activity=activity; // 计算参数 cal(activity); // 初始化对象 init(activity); } public static HighLightGuideView builder(Activity activity) { return new HighLightGuideView(activity); } /** * 计算参数 * * @param context 上下文环境引用 */ private void cal(Context context) { // 获取屏幕尺寸数组 int[] screenSize = MeasureUtil.getScreenSize((Activity) context); // 获取屏幕宽高 screenW = screenSize[0]; screenH = screenSize[1]; } /** * 初始化对象 */ private void init(Context context) { tipBitmaps = new ArrayList<>(); targetViews = new ArrayList<>(); rootView = ((Activity) getContext()).findViewById(android.R.id.content); // 实例化画笔并开启其抗锯齿和抗抖动 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); // 设置画笔透明度为0是关键! mPaint.setARGB(0, 255, 0, 0); // 设置混合模式为DST_IN mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); BlurMaskFilter.Blur blurStyle = null; switch (maskblurstyle) { case MASKBLURSTYLE_SOLID: blurStyle = BlurMaskFilter.Blur.SOLID; break; case MASKBLURSTYLE_NORMAL: blurStyle = BlurMaskFilter.Blur.NORMAL; break; } mPaint.setMaskFilter(new BlurMaskFilter(15, blurStyle)); // 生成前景图Bitmap fgBitmap = Bitmap.createBitmap(screenW, screenH, Bitmap.Config.ARGB_4444); // 将其注入画布 mCanvas = new Canvas(fgBitmap); // 绘制前景画布颜色 mCanvas.drawColor(maskColor); // 实例化箭头图片 jtDownRight = BitmapFactory.decodeResource(getResources(), R.drawable.jt_down_right); jtDownLeft = BitmapFactory.decodeResource(getResources(), R.drawable.jt_down_left); jtUpLeft = BitmapFactory.decodeResource(getResources(), R.drawable.jt_up_left); jtUpRight = BitmapFactory.decodeResource(getResources(), R.drawable.jt_up_right); } @Override protected void onDraw(Canvas canvas) { if (targetViews == null && tipBitmaps == null) return; // 绘制前景 canvas.drawBitmap(fgBitmap, 0, 0, null); //有高亮控件 if (targetViews.size() > 0 && tipBitmaps.size() > 0) { for (int i = 0; i < targetViews.size(); i++) { //高亮控件宽高 int vWidth = targetViews.get(i).getWidth(); int vHeight = targetViews.get(i).getHeight(); //获取获取高亮控件坐标 int left = 0; int top = 0; int right = 0; int bottom = 0; try { Rect rtLocation =ViewUtils.getLocationInView(((ViewGroup)activity.findViewById(Window.ID_ANDROID_CONTENT)).getChildAt(0),targetViews.get(i)); left = rtLocation.left; top = rtLocation.top; right = rtLocation.right; bottom = rtLocation.bottom; Log.d("statusheightssleft",left+""); Log.d("statusheightsstop",top+""); Log.d("statusheightbottom",right+""); Log.d("statusheightsbottom",bottom+""); } catch (Exception e) { e.printStackTrace(); } //绘制高亮形状 switch (highLightStyle) { case VIEWSTYLE_OVAL: RectF rectf = new RectF(left-highLisghtPadding, top-highLisghtPadding, right+highLisghtPadding, bottom+highLisghtPadding); mCanvas.drawOval(rectf, mPaint); break; case VIEWSTYLE_RECT: RectF rect = new RectF(left - borderWitdh-highLisghtPadding, top - borderWitdh-highLisghtPadding, right + borderWitdh+highLisghtPadding, bottom + borderWitdh+highLisghtPadding); mCanvas.drawRoundRect(rect, 20, 20, mPaint); break; case VIEWSTYLE_CIRCLE: default: radius = vWidth > vHeight ? vWidth / 2 +highLisghtPadding/2 : vHeight / 2+ highLisghtPadding/2; if (radius < 50) { radius = 100; } mCanvas.drawCircle(left + vWidth / 2, top + vHeight / 2, radius, mPaint); break; } //绘制箭头和提示图 if (bottom < screenH / 2 || (screenH / 2 - top > bottom - screenH / 2)) {// 偏上 int jtTop = highLightStyle == VIEWSTYLE_CIRCLE ? bottom +highLisghtPadding + margin+radius/3 : bottom +highLisghtPadding+ margin; if (right < screenW / 2 || (screenW / 2 - left > right - screenW / 2)) {//偏左 canvas.drawBitmap(jtUpLeft, left + vWidth / 2, jtTop, null); if (tipBitmaps.get(i) != null) { canvas.drawBitmap(tipBitmaps.get(i), left + vWidth / 2, jtTop + jtUpLeft.getHeight(), null); } } else { canvas.drawBitmap(jtUpRight, left + vWidth / 2 - 100 - margin, jtTop, null); if (tipBitmaps.get(i) != null) { canvas.drawBitmap(tipBitmaps.get(i), left + vWidth / 2 - 100 - tipBitmaps.get(i).getWidth() / 2, jtTop + jtUpRight.getHeight(), null); } } } else { int jtTop = highLightStyle == VIEWSTYLE_CIRCLE ? top - jtDownLeft.getHeight()-radius/3 -highLisghtPadding- margin : top - jtDownLeft.getHeight() - margin-highLisghtPadding; if (right < screenW / 2 || (screenW / 2 - left > right - screenW / 2)) { canvas.drawBitmap(jtDownLeft, left + vWidth / 2, jtTop, null); if (tipBitmaps.get(i) != null) { canvas.drawBitmap(tipBitmaps.get(i), left + vWidth / 2, jtTop - tipBitmaps.get(i).getHeight(), null); } } else { canvas.drawBitmap(jtDownRight, left + vWidth / 2 - 100 - margin, jtTop, null); if (tipBitmaps.get(i) != null) { canvas.drawBitmap(tipBitmaps.get(i), left + vWidth / 2 - 100 - tipBitmaps.get(i).getWidth() / 2 - margin, jtTop - tipBitmaps.get(i).getHeight(), null); } } } } } //无高亮控件,只是显示提示图片(仅能提示一张) else if (tipBitmaps.size() > 0) { canvas.drawBitmap(tipBitmaps.get(0), (screenW - tipBitmaps.get(0).getWidth()) / 2, (screenH - tipBitmaps.get(0).getHeight()) / 2, null); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP:// if (touchOutsideCancel) { this.setVisibility(View.GONE); //移除view if (rootView != null) { ((ViewGroup) rootView).removeView(this); } //返回监听 if (this.onDismissListener != null) { onDismissListener.onDismiss(); } return true; } break; } return true; } public interface OnDismissListener { public void onDismiss(); } /********************builder模式设置属性******************************/ /** * 绘制前景画布颜色 * * @param bgColor */ public HighLightGuideView setMaskColor(int bgColor) { try { this.maskColor = ContextCompat.getColor(getContext(),bgColor); // 重新绘制前景画布 mCanvas.drawColor(maskColor); } catch (Exception e) { e.printStackTrace(); } return this; } /** * 设置高亮显示类型 * * @param style */ public HighLightGuideView setHighLightStyle(int style) { this.highLightStyle = style; return this; } /** * 设置高亮画笔类型 * * @param maskblurstyle */ public HighLightGuideView setMaskblurstyle(int maskblurstyle) { this.maskblurstyle = maskblurstyle; return this; } /** * 设置需要高亮的View和提示的图片 * * @param targetView * @param res */ public HighLightGuideView addHighLightGuidView(View targetView, int res) { try { targetViews.add(targetView); tipBitmaps.add(BitmapFactory.decodeResource(getResources(), res)); } catch (Exception e) { e.printStackTrace(); } return this; } /** * 设置不需要高亮的View,只是提示图片 * * @param res */ public HighLightGuideView addNoHighLightGuidView(int res) { try { tipBitmaps.add(BitmapFactory.decodeResource(getResources(), res)); } catch (Exception e) { e.printStackTrace(); } return this; } /** * 设置外部是否关闭,默认关闭 * * @param cancel */ public HighLightGuideView setTouchOutsideDismiss(boolean cancel) { this.touchOutsideCancel = cancel; return this; } /** * 设置额外的边框宽度 * * @param borderWidth */ public HighLightGuideView setBorderWidth(int borderWidth) { this.borderWitdh = borderWidth; return this; } /** * 设置状态栏高度 默认是减去了一个状态栏高度 如果主题设置android:windowTranslucentStatus=true * 需要设置状态栏高度为0 * * @param highLisghtPadding */ public HighLightGuideView setHighLisghtPadding(int highLisghtPadding) { this.highLisghtPadding = highLisghtPadding; return this; } /** * 设置关闭监听 * * @param listener */ public HighLightGuideView setOnDismissListener(OnDismissListener listener) { this.onDismissListener = listener; return this; } /** * 清空画布 */ public HighLightGuideView clearBg() { if (mCanvas != null) { Paint paint = new Paint(); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); mCanvas.drawPaint(paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); } // 将其注入画布 mCanvas = new Canvas(fgBitmap); // 绘制前景画布 mCanvas.drawColor(maskColor); return this; } /** * 显示 */ public void show() { if (rootView != null) { ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams (ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); ((ViewGroup) rootView).addView(this, ((ViewGroup) rootView).getChildCount(), lp); } } }