Android初級(jí)開發(fā)筆記 -- Android事件分發(fā)

之前寫過一篇淺談Android事件分發(fā)。有興趣的旁友可猛戳-〉淺談Android事件分發(fā)。

今日主要是寫一下實(shí)戰(zhàn)例子。下面這個(gè)例子是摘抄了Android事件分發(fā)機(jī)制詳解與實(shí)戰(zhàn)剖析,一張事件分發(fā)流程圖,讓你徹底搞明白的實(shí)例。

實(shí)現(xiàn)效果如下,底部的行程詳情可以往上拖動(dòng)覆蓋在地圖之上,也可以往下拖動(dòng)停止在屏幕的正中位置,地圖相關(guān)操作: 放大、縮小、移動(dòng)都能正常的響應(yīng),怎么實(shí)現(xiàn)?


在這里插入圖片描述

針對(duì)上面的例子,我們來看一下源碼。

一:布局文件

<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"
        />
    //占據(jù)整個(gè)頁面
    <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是層疊的視圖,下一個(gè)組件會(huì)疊加在上一個(gè)上方。左頂點(diǎn)為左上角。

TransScrollView里面包含的是一個(gè)LinearLayout1,

LinearLayout1里面包含了自定義的TransparentView和一個(gè)包含了各種組件的LinearLayout2。

TransparentView跟地圖組件一樣高,位于頂端,也就是和地圖同個(gè)位置(未滑動(dòng)時(shí))只是ta是透明的。

二:自定義 TransparentView

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,設(shè)置根據(jù)接口實(shí)現(xiàn)方法返回值進(jìn)行返回
    @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;
    }
}

四:事件分發(fā)處理

mTransparentView = findViewById(R.id.view_tansparent);
//實(shí)現(xiàn)TouchEventListener的dispatchTouchEvent方法,將點(diǎn)擊事件傳給地圖控件進(jìn)行處理
mTransparentView.setListener(new TransparentView.TouchEventListener() {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        return mMapView.dispatchTouchEvent(event);
    }
});
mScrollView = findViewById(R.id.view_scrollview);
//實(shí)現(xiàn)TouchEventListener的dispatchTouchEvent方法,
//若點(diǎn)擊位置在TransparentView區(qū)域,那么返回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)點(diǎn)
        //Returns true if (x,y) is inside the rectangle.
        //判斷點(diǎn)擊處是否在這個(gè)矩形內(nèi)
        if(rect.contains((int)event.getX(),(int)event.getY())){
            return true;
        }else{
            return false;
        }
    }
});

來~總結(jié)一下:
該例子,布局為兩層,三大塊,一塊是地圖,一塊是TransparentView,一塊是LinearLayout2包含的各種組件view。

那么在點(diǎn)擊到地圖的時(shí)候,事件自然給其處理。點(diǎn)擊到TransparentView也應(yīng)該是給地圖,所以在TouchEventListener接口的dispatchTouchEvent中進(jìn)行了處理。點(diǎn)擊到LinearLayout2,根據(jù)情況判斷是否攔截,或者傳給不同的控件進(jìn)行處理。

還不明白?那么再重點(diǎn)解釋一下如何實(shí)現(xiàn)TransparentView的事件最后交給了地圖控件處理。

首先當(dāng)我們點(diǎn)擊了TransparentView的時(shí)候,【TransparentView [View] 是包含在TransScrollView [ViewGroup] 里面的】
(1)執(zhí)行TransScrollView的dispatchTouchEvent方法,沒有重載,好的默認(rèn)返回。
(2)接著是TransScrollView的onInterceptTouchEvent方法,該方法被重載。

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

根據(jù)是否實(shí)現(xiàn)了TouchEventListener,以及該接口方法的返回值進(jìn)行返回。由于實(shí)現(xiàn)了,

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)點(diǎn)
        //Returns true if (x,y) is inside the rectangle.
        //判斷點(diǎn)擊處是否在這個(gè)矩形內(nèi)
        if(rect.contains((int)event.getX(),(int)event.getY())){
            return true;
        }else{
            return false;
        }
    }
});

而且因?yàn)辄c(diǎn)擊的是TransparentView的矩形區(qū)域,所以該接口方法返回true。

【注意:上面那段代碼的的dispatchTouchEvent不是事件分發(fā)中的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也實(shí)現(xiàn)了TouchEventListener接口,

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

那么返回的是接口方法的返回值。至此,點(diǎn)擊事件傳給了地圖控件處理。

分享交流才能更好成長,如果文章有任何錯(cuò)誤之處,懇請(qǐng)各位看官不吝賜教,萬分感激~

內(nèi)推信息

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容