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)

 

你可能感兴趣的:(Android,自定义控件分享,开发分享,日常开发分享)