Android探究事件分發(fā)

以前沒太注意,很久沒用之后再使用發(fā)現(xiàn)有些地方模糊了例证,就是那種不知道是對是錯的感覺,然后又要重復(fù)上網(wǎng)去找資料迷捧,所以打算自己整理一篇织咧,有很多時(shí)候,一些特殊的需要要是能巧妙的運(yùn)用事件分發(fā)機(jī)制其實(shí)能很快的去解決問題漠秋。

一.流程

1.打印全流程

對于activity,viewgroup和view來說笙蒙,如果不再任意一個(gè)流程消費(fèi)事件,就會打印出這個(gè)結(jié)果庆锦。

image.png

這個(gè)就不用多解釋了捅位,如果都沒消費(fèi)事件,會在最后一句打印出ACTION_DOWN沒有被處理搂抒。

2.圖解過程

由上面打印的過程可以做出下面一張事件分發(fā)時(shí)的流程圖:

image.png

但是在activity艇搀,viewgroup和view的dispatchTouchEvent、onTouchEvent這些方法中求晶,返回值是一個(gè)布爾類型的焰雕,有三種情況,false誉帅,true和super淀散,分別對這三種情況和分發(fā)流程進(jìn)行探究后得到下圖:

image.png

圖太麻煩了,我就不重新畫了蚜锨,從網(wǎng)上找了一張档插,不同的是,圖中的onTouchEvent亚再,我試過郭膛,如果傳的是super,是會被消費(fèi)的氛悬,而不是返回上一層则剃。

3.一般情況下的事件分發(fā)

上面的情況我是重寫viewgroup重寫view去重寫onTouchEvent和dispatchTouchEvent方法,但是實(shí)際操作中不會總是這種情況如捅,因?yàn)槲覀儾豢赡馨呀佑|到事件分發(fā)需求的控件都重寫棍现,那樣就太麻煩了。所以先來看看一般情況下的分發(fā)情況镜遣。

我把自定義view換成普通的view然后寫onClick方法己肮,打印以下結(jié)果

image.png

發(fā)現(xiàn)在onClick事件中,view會消費(fèi)事件,即便你在onClick中沒做什么操作谎僻,事件也會被view給消費(fèi)娄柳,那不寫onClick方法呢?

image.png

發(fā)現(xiàn)打印結(jié)果中艘绍,即便沒對View監(jiān)聽赤拒,事件也不會往上傳,然后我打算看看view中的源碼

image.png

我* 诱鞠, 看來我本地是看不了了挎挖,別的地方找找。如果你看到了源碼航夺,你會發(fā)現(xiàn)臥槽真尼瑪多肋乍,一大堆判斷。我就找來了一個(gè)別人整理過的所寫版的敷存。感謝這位大神,很有良心堪伍。

if (((viewFlags & CLICKABLE) == CLICKABLE ||(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
    (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
    switch (action) {
        case MotionEvent.ACTION_UP:
            boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
            if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                ...
                if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                    // This is a tap, so remove the longpress check
                    removeLongPressCallback();

                    // Only perform take click actions if we were in the pressed state
                    if (!focusTaken) {
                        // Use a Runnable and post this rather than calling
                        // performClick directly. This lets other visual state
                        // of the view update before click actions start.
                        if (mPerformClick == null) {
                            mPerformClick = new PerformClick();
                        }
                        if (!post(mPerformClick)) {
                            performClick();
                        }
                    }
                }
            ...
            break;
        ...
    }
    return true;
}

看得出默認(rèn)的情況下锚烦,返回true也就是被消費(fèi)。我看了源碼就知道了帝雇,當(dāng)然沒貼出來涮俄,這里設(shè)置setClickable的話就會有神奇的效果,我設(shè)置view.setClickable(false);
打印出下面的結(jié)果尸闸。

image.png

所以能得出一個(gè)簡單的結(jié)論彻亲,一般情況下你不從寫view,要讓這個(gè)view的事件往上層分發(fā)吮廉,需要設(shè)置setClickable(false)

那有的朋友說苞尝,我要有那種點(diǎn)擊view之后,view先做操作宦芦,然后viewgroup在做操作宙址,而且還不是自定義view和viewgrou的條件下。如果是直接對View設(shè)置onClickListener的話是無法達(dá)到這個(gè)效果的调卑,所以只能對view設(shè)置OnTouchListener

btnContent.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                    Log.v("mmp", "view->setOnTouchListener");
                }
                return false;
            }
        });

這樣就能先執(zhí)行view的點(diǎn)擊事件抡砂,再執(zhí)行viewgroup的點(diǎn)擊事件。

image.png
4.總結(jié)

事件分發(fā)有意思的地方就在于恬涧,你想讓什么去觸發(fā)這個(gè)事件注益,并且是否分發(fā)給上一層去做處理,更有意思的地方在于這個(gè)機(jī)制是先向下分發(fā),由activity分發(fā)給viewgroup再分發(fā)給view,之后執(zhí)行是向上執(zhí)行崭别,先由view執(zhí)行塘偎。所以它使用起來會很靈活琉历,比如說你想做一系列的點(diǎn)擊事件硼端,點(diǎn)擊一個(gè)按鈕后activity先執(zhí)行某步操作亚兄,view再執(zhí)行某步操作低滩,然后activity再執(zhí)行某部操作顽冶,這個(gè)做法也是可以做到的欺抗。

二.事件分發(fā)的靈活用法

事件分發(fā)他是一個(gè)機(jī)制,所以它可以適用于很多的場景强重,不要說它只能用于處理特殊的點(diǎn)擊事件绞呈,那可真是暴殄天物。

1.防止快速點(diǎn)擊

我們可以用事件分發(fā)機(jī)制來防止快速點(diǎn)擊间景,如果對一個(gè)按鈕就行快速點(diǎn)擊那就會出現(xiàn)很糟糕的后果佃声,所以一般的app中又要做防止快速點(diǎn)擊的操作,有些人對一些按鈕重復(fù)進(jìn)行快速點(diǎn)擊的操作倘要,那就很浪費(fèi)時(shí)間圾亏,可以直接在activity中做處理。

重寫activity的dispatchTouchEvent方法封拧,記錄最后一次觸發(fā)點(diǎn)擊事件的事件志鹃,每次點(diǎn)擊都獲取時(shí)間,如果兩個(gè)時(shí)間相減小于XXX秒泽西,就返回true曹铃,這樣快速點(diǎn)擊的時(shí)候事件就不會分發(fā)下去,大于這個(gè)時(shí)間就返回super捧杉。

在activity中寫

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (System.currentTimeMillis() - lastTime < 500) {
                return true;
            }
        }
        return super.dispatchTouchEvent(ev);
    }

當(dāng)然除了這樣子做之外陕见,你也可以自己寫個(gè)根布局,然后所有xml中的布局都寫這個(gè)根布局味抖,再用viewgroup的onInterceptTouchEvent來攔截也行评甜。

2.仿dialog點(diǎn)擊外部內(nèi)容消失效果

我也是因?yàn)檫@個(gè)需求所以才想寫這個(gè)文章大,假如我要做一個(gè)圖層仔涩,實(shí)現(xiàn)在recyclerview的item中彈出的效果蜕着,對item的彈框效果的圖層,如果你是用一種圖層的思想你就知道這個(gè)圖層應(yīng)該是做在item上红柱,activity下承匣,所以無法使用dialog或popupwindow,因?yàn)檫@兩個(gè)彈框都是頂層的圖層锤悄,所以只能加一層布局來顯示和隱藏達(dá)到效果韧骗。而要實(shí)現(xiàn)這個(gè)效果,可以在activity的dispatchTouchEvent中加判斷零聚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末袍暴,一起剝皮案震驚了整個(gè)濱河市些侍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌政模,老刑警劉巖岗宣,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異淋样,居然都是意外死亡耗式,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門趁猴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刊咳,“玉大人,你說我怎么就攤上這事儡司∮榘ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵捕犬,是天一觀的道長跷坝。 經(jīng)常有香客問我,道長碉碉,這世上最難降的妖魔是什么探孝? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮誉裆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缸濒。我一直安慰自己足丢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布庇配。 她就那樣靜靜地躺著斩跌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捞慌。 梳的紋絲不亂的頭發(fā)上耀鸦,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機(jī)與錄音啸澡,去河邊找鬼袖订。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嗅虏,可吹牛的內(nèi)容都是我干的洛姑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼皮服,長吁一口氣:“原來是場噩夢啊……” “哼楞艾!你這毒婦竟也來了参咙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤硫眯,失蹤者是張志新(化名)和其女友劉穎蕴侧,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體两入,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡净宵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谆刨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片塘娶。...
    茶點(diǎn)故事閱讀 38,569評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖痊夭,靈堂內(nèi)的尸體忽然破棺而出刁岸,到底是詐尸還是另有隱情,我是刑警寧澤她我,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布虹曙,位于F島的核電站,受9級特大地震影響番舆,放射性物質(zhì)發(fā)生泄漏酝碳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一恨狈、第九天 我趴在偏房一處隱蔽的房頂上張望疏哗。 院中可真熱鬧,春花似錦禾怠、人聲如沸返奉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芽偏。三九已至,卻和暖如春弦讽,著一層夾襖步出監(jiān)牢的瞬間污尉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工往产, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留被碗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓仿村,卻偏偏與公主長得像蛮放,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子奠宜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容