要實現(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,在這就不多提了。