以前寫過一篇淺談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);
}
});
複製代碼
那麼返回的是接口方法的返回值。至此,點擊事件傳給了地圖控件處理。
分享交流才能更好成長,若是文章有任何錯誤之處,懇請各位看官不吝賜教,萬分感激~