美文网首页
指示View

指示View

作者: 叶落清秋 | 来源:发表于2018-12-26 11:02 被阅读11次

要实现的东西也比较简单。先来看看效果:

一个简单的view

效果看完了,看看是怎么实现的吧。
首先,使用方面,只要一句话,是不是比较简单。

GuideFun.makeFun(findViewById(R.id.tv),R.layout.view_guide).show();

这种使用方式是不是很熟悉,对的 , 和SnackBar的使用方式相同,一起来看看SnackBar的简单使用:

 Snackbar.make(view, "已删除一个会话", Snackbar.LENGTH_SHORT).show();

一起来看看GuideFun做了什么吧
当调用makeFun方法时,会创建GuideFun对象,将值传给构造函数

public GuideFun(View anchorView , int resId) {
    //1.渲染布局进来
    view = LayoutInflater.from(anchorView.getContext()).inflate(resId, null, false);
    GuideView guideView = (GuideView)view.findViewById(R.id.guideView);
    //2.找到FrameLayout id 为content
    parent = findSuitableParent(anchorView);
    guideView.bindViewGroup(parent);
}

构造函数中,最主要的是找个了一个id 为content的FrameLayout,来看看是怎么找到的:

private static ViewGroup findSuitableParent(View view) {
    do {
        if (view instanceof FrameLayout) {
            //找到id为content的FrameLayout
            if (view.getId() == android.R.id.content) {
                return (ViewGroup) view;
            }
        }

        if (view != null) {
            final ViewParent parent = view.getParent();
            view = parent instanceof View ? (View) parent : null;
        }
    } while (view != null);

    return null;
}

是的,这个方法是我从SnackBar源码中抽出来的方法,使用起来很方便。同时我们来看看为什么要找到这个id为content的上层FrameLayout。

网上剪切来的图

android的顶层view是DecorView,而我们在Activity中setContentView的布局都将加载到id为content的FrameLayout。所以,当我们在将guideView加到content中,就位于Activity的布局之上。这样,就没用什么可以阻挡我们了。

我们要怎么来找到点击的位于guideView之下的那些控件呢?
我们只需要根据触摸的x、y值,通过父类逐级向下遍历,如果子孩子不为ViewGroup,那么判断触摸点是否在他上面就可以了。

//遍历viewGroup
//view ,bindViewGroup传入的parent
//rawX,rawY触摸点的x、y
private View getPointViewInfo(View view,int rawX, int rawY){
    if(null == view) {
        return null;
    }
    if(view instanceof ViewGroup) {
        ViewGroup viewGroup = (ViewGroup) view;
        LinkedList<ViewGroup> queue = new LinkedList<>();
        queue.add(viewGroup);
        while(!queue.isEmpty()) {
            //取出并删除节点
            ViewGroup current = queue.removeFirst();
            for(int i = 0; i < current.getChildCount(); i ++) {
                View child = current.getChildAt(i);
                if(child instanceof ViewGroup) {
                    //加入链表末尾
                    queue.addLast((ViewGroup)child);
                    continue;
                }
                // View view;
                if((child instanceof GuideView)){
                    //不能是自身
                    continue;
                }
                rect=calcViewScreenLocation(child);
                if(rect.contains(rawX, rawY)){
                    //找到view,返回
                    return child;
                }
            }
        }
    }
    return null;
}

返回view的边框矩形

/**
* 计算指定的 View 在屏幕中的坐标。
*/
public static RectF calcViewScreenLocation(View view) {
    int[] location = new int[2];
    // 获取控件在屏幕中的位置,返回的数组分别为控件左顶点的 x、y 的值
    view.getLocationOnScreen(location);
    return new RectF(location[0], location[1], location[0] + view.getWidth(),location[1] + view.getHeight());
}

剩下的就是绘制和动画了,比较简单,有兴趣的可以看看[源码]: https://github.com/leaf-fade/GuideView,在这就不多提了。

相关文章

网友评论

      本文标题:指示View

      本文链接:https://www.haomeiwen.com/subject/hyajyxtx.html