Android初級開發筆記 -- Android事件分發

以前寫過一篇淺談Android事件分發。有興趣的旁友可猛戳-〉淺談Android事件分發java

今日主要是寫一下實戰例子。下面這個例子是摘抄了Android事件分發機制詳解與實戰剖析,一張事件分發流程圖,讓你完全搞明白的實例。android

實現效果以下,底部的行程詳情能夠往上拖動覆蓋在地圖之上,也能夠往下拖動中止在屏幕的正中位置,地圖相關操做: 放大、縮小、移動都能正常的響應,怎麼實現? api

在這裏插入圖片描述
針對上面的例子,咱們來看一下源碼。

一:佈局文件ide

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <com.amap.api.maps.MapView
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        />
    //佔據整個頁面
    <com.zhijiaxing.travel.trip.record.view.TransScrollView
        android:id="@+id/view_scrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"

        >
        //顏色爲透明
        <com.zhijiaxing.travel.trip.record.view.TransparentView
            android:id="@+id/view_tansparent"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:background="#00000000"
            />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ffffff"
            android:orientation="vertical"
            >
        </LinearLayout>

    </LinearLayout>
    </com.zhijiaxing.travel.trip.record.view.TransScrollView>
</FrameLayout>
複製代碼

咱們能夠知道FrameLayout包含的是地圖組件和自定義的TransScrollView。佈局

FrameLayout是層疊的視圖,下一個組件會疊加在上一個上方。左頂點爲左上角。spa

TransScrollView裏面包含的是一個LinearLayout1,.net

LinearLayout1裏面包含了自定義的TransparentView和一個包含了各類組件的LinearLayout2。code

TransparentView跟地圖組件同樣高,位於頂端,也就是和地圖同個位置(未滑動時)只是ta是透明的。cdn

二:自定義 TransparentViewblog

public class TransparentView extends View {
    TouchEventListener mListener;
    //定義TouchEventListener接口
    public interface TouchEventListener{
        boolean dispatchTouchEvent(MotionEvent event);
    }
    public TransparentView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

    }
	//重寫父類的dispatchTouchEvent
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if(mListener != null){
            return  mListener.dispatchTouchEvent(event);
        }else{
            return super.dispatchTouchEvent(event);
        }
    }
	//經過setListener()初始化mListener 
    public void setListener(TouchEventListener listener) {
        mListener = listener;
    }
}
複製代碼

三:自定義 TransScrollView

public class TransScrollView extends NestedScrollView {
    public TransparentView.TouchEventListener mListener;

    public TransScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
	//重寫ViewGroup中特有的onInterceptTouchEvent,設置根據接口實現方法返回值進行返回
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (mListener != null && mListener.dispatchTouchEvent(ev)) {
            return false;
        }
        return super.onInterceptTouchEvent(ev);
    }
	//經過setListener()初始化mListener 
    public void setListener(TransparentView.TouchEventListener listener) {
        mListener = listener;
    }
}
複製代碼

四:事件分發處理

mTransparentView = findViewById(R.id.view_tansparent);
//實現TouchEventListener的dispatchTouchEvent方法,將點擊事件傳給地圖控件進行處理
mTransparentView.setListener(new TransparentView.TouchEventListener() {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        return mMapView.dispatchTouchEvent(event);
    }
});
mScrollView = findViewById(R.id.view_scrollview);
//實現TouchEventListener的dispatchTouchEvent方法,
//若點擊位置在TransparentView區域,那麼返回true
mScrollView.setListener(new TransparentView.TouchEventListener() {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Rect rect = new Rect();
        //獲取TransparentView矩形範圍
        mTransparentView.getLocalVisibleRect(rect);
        //boolean contains(int x, int y)是否包含(x,y)點
		//Returns true if (x,y) is inside the rectangle.
		//判斷點擊處是否在這個矩形內
        if(rect.contains((int)event.getX(),(int)event.getY())){
            return true;
        }else{
            return false;
        }
    }
});
複製代碼

來~總結一下: 該例子,佈局爲兩層,三大塊,一塊是地圖,一塊是TransparentView,一塊是LinearLayout2包含的各類組件view。

那麼在點擊到地圖的時候,事件天然給其處理。點擊到TransparentView也應該是給地圖,因此在TouchEventListener接口的dispatchTouchEvent中進行了處理。點擊到LinearLayout2,根據狀況判斷是否攔截,或者傳給不一樣的控件進行處理。

還不明白?那麼再重點解釋一下如何實現TransparentView的事件最後交給了地圖控件處理。

首先當咱們點擊了TransparentView的時候,【TransparentView [View] 是包含在TransScrollView [ViewGroup] 裏面的】

(1)執行TransScrollView的dispatchTouchEvent方法,沒有重載,好的默認返回。 (2)接着是TransScrollView的onInterceptTouchEvent方法,該方法被重載。

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (mListener != null && mListener.dispatchTouchEvent(ev)) {
            return false;
        }
        return super.onInterceptTouchEvent(ev);
    }
複製代碼

根據是否實現了TouchEventListener,以及該接口方法的返回值進行返回。因爲實現了,

mScrollView.setListener(new TransparentView.TouchEventListener() {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Rect rect = new Rect();
        //獲取TransparentView矩形範圍
        mTransparentView.getLocalVisibleRect(rect);
        //boolean contains(int x, int y)是否包含(x,y)點
		//Returns true if (x,y) is inside the rectangle.
		//判斷點擊處是否在這個矩形內
        if(rect.contains((int)event.getX(),(int)event.getY())){
            return true;
        }else{
            return false;
        }
    }
});
複製代碼

並且由於點擊的是TransparentView的矩形區域,因此該接口方法返回true。

【注意:上面那段代碼的的dispatchTouchEvent不是事件分發中的dispatchTouchEvent,而是接口定義的dispatchTouchEvent】

那麼TransScrollView的onInterceptTouchEven返回的是false,不攔截。

(3)好嘞~接下來事件傳給了TransparentView的dispatchTouchEvent,該方法被重載。

@Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if(mListener != null){
            return  mListener.dispatchTouchEvent(event);
        }else{
            return super.dispatchTouchEvent(event);
        }
    }
複製代碼

TransparentView也實現了TouchEventListener接口,

mTransparentView.setListener(new TransparentView.TouchEventListener() {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        return mMapView.dispatchTouchEvent(event);
    }
});
複製代碼

那麼返回的是接口方法的返回值。至此,點擊事件傳給了地圖控件處理。

分享交流才能更好成長,若是文章有任何錯誤之處,懇請各位看官不吝賜教,萬分感激~

相關文章
相關標籤/搜索