自定义高亮区域 作用户引导的思路

来源:互联网 发布:淘宝分享有礼怎样计费 编辑:程序博客网 时间:2024/04/28 09:24

先显示简易的效果

网上看了一些引导 发现自定义文本 和箭头指向都不够方便,就写了比较符合自己习惯的

//内容更新
视觉优化 将下面代码分别添加到两个addView之后

  ObjectAnimator.ofFloat(高亮的view, "scaleY", 0.5f, 1.0f).setDuration(800).start();  ObjectAnimator.ofFloat(显示文本, "scaleX", 0.5f, 1.0f).setDuration(800).start();  ObjectAnimator.ofFloat(显示文本, "scaleY", 0.5f, 1.0f).setDuration(800).start();

效果如下
这里写图片描述

相关Module下载

1.已经实现的有3种简易功能

一种是连接两个高亮的view 提示语句在线(View)的中间
二是指向某一条文件
三是多个高亮区域的连接

核心思路就是遮盖一层。我选择直接放在根布局下面。当然你想 直接动态添加的方式也行。目前只是探讨一下思路。
通过传入的view` Region region = new Region(new Region(0, 0, getWidth(), getHeight()));

    for (int i = 0; i < rects.size(); i++) {        Region region0 = new Region(rects.get(i));        region.op(region0, Region.Op.DIFFERENCE);    }    RegionIterator iterator = new RegionIterator(region);    Rect rectNew = new Rect();    while (iterator.next(rectNew)) {        canvas.drawRect(rectNew, paint);    }`

扣出高亮区域然后连线添加文本 剩下的就是具体坐标和角度的计算。

    @Override    protected void dispatchDraw(Canvas canvas) {        //核心顺序        if (rects.size() != 0) {            drawRect(canvas);//绘制高亮区域            super.dispatchDraw(canvas);//绘制子view -->如提示文字 箭头        }    }

为了大家方便自定义自己的 指向箭头。我没有画这条线 而是留了一个简易的view。可以用自己ui设计的箭头去替换 那么你可能就需要加上 图片宽度带来的影响

使用方法简易示例

  //盖在根布局最上层 可指定其他任意层级的view高亮 链接 提示        gcv = (GuideCoverView) findViewById(R.id.gcv);        //后期可改进为 动态添加//        gcv.doubleViewContact(view, view2, 0, "这是一个提示??", false);        gcv.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Log.i("rex", "v");                int c = index++ % 5;                //第三处参数为 链接线的 自定义view 此处仅传图片资源id 传0即默认黄线 如需要其他自定义或者网络图片 可以去内部自定义addArr                if (c == 0) {                    gcv.doubleViewContact(view, view2, 0, "这是一个提示~~", false);                } else if (c == 1) {                    gcv.doubleViewContact(view, view3, 0, "这又是一个提示??", false);                } else if (c == 2) {                    gcv.doubleViewContact(view2, view3, 0, "这又他妈是一个提示??", false);                } else if (c == 3) {                    gcv.doubleViewContact(view, view4, 0, "熄火区域", true);                } else {                    //第二种多连接示例                    gcv.manyViewContact(                            asList(view, view2, view2, view3, view3, view4, view4,view),                            asList("多连接示例1", "多连接示例2", "多连接示例3", "多连接示例4"),                            asList(false, false, false, true)                    );                }            }        });

核心自定义遮盖引导层

package com.rex;import android.animation.ObjectAnimator;import android.animation.PropertyValuesHolder;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Region;import android.graphics.RegionIterator;import android.os.Build;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.View;import android.view.ViewTreeObserver;import android.widget.FrameLayout;import android.widget.ImageView;import android.widget.TextView;import org.w3c.dom.Text;import java.util.ArrayList;import java.util.List;/** * Created by  Rex on 2017/1/4. * 比较开放性便于自定义文字 联系线的高亮引导容器 */public class GuideCoverView extends FrameLayout {    private List<Rect> rects = new ArrayList<>();    private Paint paint;    private int padding = 8;    private int index;    private View lastView;    private int statusBarHeight;    private boolean isOnlyOneViewToText;    private int mResourId = 0;    private Canvas mCanvas;    public GuideCoverView(Context context) {        this(context, null);    }    public GuideCoverView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public GuideCoverView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init() {        statusBarHeight = getStatusBarHeight();        paint = new Paint();        paint.setColor(Color.parseColor("#8c000000"));    }    public View addArr(int w, int h) {        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(w, h);        View view = new View(getContext());        if (mResourId > 0)            view.setBackgroundResource(mResourId);        else            view.setBackgroundColor(Color.GREEN);        addView(view, lp);        return view;    }    /**     * @param viewC1     * @param viewC2     * @param id     这里示例为 两个view高亮  自定义图片作为连接示意   线中心作为 提示语     * @param isText 是否为单高亮 末端指向文字   此时另一个view决定了文本显示的位置     */    public void doubleViewContact(final View viewC1, final View viewC2, final int id, final String msg, final boolean isText) {        clear();        HighlightView(viewC1, msg, isText);        HighlightView(viewC2, msg, isText);        invalidate();    }    public void manyViewContact(ArrayList<View> views, ArrayList<String> msg, ArrayList<Boolean> isText) {        clear();        for (int i = 0; i < views.size(); i++) {            if (i + 1 >= views.size())                return;            int j = i / 2;            Log.i("rex", "j-->" + j + "msg-->" + msg.get(j) + "boolean--->" + isText.get(j));            HighlightView(views.get(i), msg.get(j), isText.get(j));            ++i;            HighlightView(views.get(i), msg.get(j), isText.get(j));            invalidate();        }    }    @Override    protected void dispatchDraw(Canvas canvas) {        //核心顺序        if (rects.size() != 0) {            drawRect(canvas);//绘制高亮区域            super.dispatchDraw(canvas);//绘制子view -->如提示文字 箭头        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);    }    public void clear() {        rects.clear();        lastView = null;        removeAllViews();        invalidate();    }    private void drawRect(Canvas canvas) {        Region region = new Region(new Region(0, 0, getWidth(), getHeight()));        for (int i = 0; i < rects.size(); i++) {            Region region0 = new Region(rects.get(i));            region.op(region0, Region.Op.DIFFERENCE);        }        RegionIterator iterator = new RegionIterator(region);        Rect rectNew = new Rect();        while (iterator.next(rectNew)) {            canvas.drawRect(rectNew, paint);        }    }    public void HighlightView(final View viewH, final String msg, final boolean isText) {        ViewTreeObserver vto = viewH.getViewTreeObserver();        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {            @Override            public void onGlobalLayout() {                //监听一次马上结束                if (Build.VERSION.SDK_INT < 16) {                    viewH.getViewTreeObserver().removeGlobalOnLayoutListener(this);                } else {                    viewH.getViewTreeObserver().removeOnGlobalLayoutListener(this);                }                int[] locationXy = getLocationXy(viewH);                Rect rect = new Rect(locationXy[0] - padding,                        locationXy[1] - statusBarHeight - padding,                        locationXy[0] + viewH.getMeasuredWidth() + padding,                        locationXy[1] + viewH.getMeasuredHeight() - statusBarHeight + padding);                if (lastView == null) {                    rects.add(rect);                    lastView = viewH;                } else {                    if (!isText) {                        rects.add(rect);//是否高亮                    }                    ContactDouble(lastView, viewH, msg, isText);                    lastView = null;                }            }        });    }    /**     * 高亮view指向文本     *     * @param view     */    private void ContactText(View view) {    }    /**     * 用自定义的view连接两个     *     * @param viewC1     * @param viewC2     * @param isText     */    private void ContactDouble(View viewC1, View viewC2, final String msg, final boolean isText) {        int[] locationXy = getLocationXy(viewC1);        int[] locationXy2 = getLocationXy(viewC2);        final int x1 = locationXy[0] + viewC1.getWidth() / 2 - 2;        final int x2 = locationXy2[0] + viewC2.getWidth() / 2;        final int y1 = locationXy[1];        final int y2 = locationXy2[1];        final int lenth = (int) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) - 20 * padding;        final View view = addArr(3, lenth);        float tan = (x1 - x2) * 1.0f / (y1 - y2);        final float du = -(float) Math.toDegrees(Math.atan(tan));        ViewTreeObserver vto = view.getViewTreeObserver();        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {            @Override            public void onGlobalLayout() {                //监听一次马上结束                if (Build.VERSION.SDK_INT < 16) {                    view.getViewTreeObserver().removeGlobalOnLayoutListener(this);                } else {                    view.getViewTreeObserver().removeOnGlobalLayoutListener(this);                }                final int centerX = (x1 + x2) / 2 - 4 * padding;                final int centerY = (y1 + y2) / 2 - view.getHeight() / 2 - 4 * padding;                view.setX(centerX);                view.setY(centerY);                view.setRotation(du);                FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);                final TextView tv = new TextView(getContext());                tv.setText(msg);                tv.setGravity(Gravity.CENTER);                if (isText) {                    //线顶端                    MeasureWH(tv, new measureOk() {                        @Override                        public void ok(View view, int w, int h) {                            view.setX(centerX + w / 2);                            view.setY(centerY);                        }                    });                } else {                    //线中间                    tv.setX((x1 + x2) / 2 + 2 * padding);                    tv.setY((y1 + y2) / 2 + 2 * padding);                }                tv.setTextColor(Color.WHITE);                addView(tv, params);            }        });    }    /**     * 获取屏幕的坐标(包括状态栏等)     */    public int[] getLocationXy(View viewL) {        int[] lXy = new int[2];        viewL.getLocationOnScreen(lXy);        LogI("getLocationXy", lXy.toString());        return lXy;    }    /**     * 监听绘制完成后测量宽高     */    public interface measureOk {        void ok(View view, int w, int h);    }    public static void MeasureWH(final View viewL, final measureOk impl) {        ViewTreeObserver vto = viewL.getViewTreeObserver();        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {            @Override            public void onGlobalLayout() {                //监听一次马上结束                if (Build.VERSION.SDK_INT < 16) {                    viewL.getViewTreeObserver().removeGlobalOnLayoutListener(this);                } else {                    viewL.getViewTreeObserver().removeOnGlobalLayoutListener(this);                }                if (impl != null) {                    impl.ok(viewL, viewL.getWidth(), viewL.getHeight());                }            }        });    }    private void LogI(String msg1, String msg2) {        LogI(msg1 + " ---- >" + msg2);    }    private void LogI(String msg) {        Log.i("rex", msg);    }    public int getStatusBarHeight() {        int result = 0;        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");        if (resourceId > 0) {            result = getResources().getDimensionPixelSize(resourceId);        }        return result;    }}
1 0