指示View

要實現(xiàn)的東西也比較簡單。先來看看效果:

一個簡單的view

效果看完了,看看是怎么實現(xiàn)的吧。
首先,使用方面,只要一句話,是不是比較簡單。

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

這種使用方式是不是很熟悉,對的 , 和SnackBar的使用方式相同,一起來看看SnackBar的簡單使用:

 Snackbar.make(view, "已刪除一個會話", Snackbar.LENGTH_SHORT).show();

一起來看看GuideFun做了什么吧
當調用makeFun方法時,會創(chuàng)建GuideFun對象,將值傳給構造函數(shù)

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);
}

構造函數(shù)中,最主要的是找個了一個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()) {
            //取出并刪除節(jié)點
            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];
    // 獲取控件在屏幕中的位置,返回的數(shù)組分別為控件左頂點的 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,在這就不多提了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容