事件攔截應(yīng)用-外部注簿、內(nèi)部攔截法

目錄
1.事件分發(fā)介紹
2.Down敢茁、up事件的分發(fā)過程
3.onTouchListener篡帕、onClickListener調(diào)用時機
4.事件攔截應(yīng)用
5.NestedScrollingParent
6.Behavior的使用
7.NestedScrollingChild接口來源
上面小節(jié)分析了時間傳遞的原理智哀,本節(jié)則主要介紹下他們的使用次询,分析需要事件攔截時應(yīng)如何處理,并介紹其原理瓷叫。即外部攔截法屯吊、內(nèi)部攔截法,代碼參考Android開發(fā)藝術(shù)探索一書摹菠,記錄心得并分析為什么這樣寫盒卸。
若ViewGroup中包裹一個View,此時滑動時需要處理之間的滑動沖突次氨,因此需要進行滑動事件的攔截蔽介,若果我們在ViewGroup中對事件進行攔截則叫外部攔截法,在View中進行事件的攔截則叫做內(nèi)部攔截法煮寡,下面主要討論Move事件的滑動攔截虹蓄。
1.外部攔截法
外部攔截法在ViewGroup中進行攔截,紅色字體為攔截條件幸撕,即當(dāng)y方向移動距離大于10是ViewGroup獲取滑動事件薇组。

外部攔截法代碼

我們主要在onInterceptTouchEvent中進行事件攔截,不攔截down事件坐儿,若攔截了down事件律胀,move事件也會在此處消耗,原因見http://www.reibang.com/p/7673bc4b5575挑童,up累铅、cancel事件我們不做攔截處理。
下面是我們外部攔截的事件傳遞圖站叼,從上節(jié)搬過來的娃兽。
外部攔截事件傳遞圖

2.內(nèi)部攔截法
內(nèi)部攔截法代碼

內(nèi)部攔截法是在View中進行攔截。此時ViewGroup尽楔、View均需要進行處理投储。然后再View中通過
requestDisallowInterceptTouchEvent()函數(shù)來控制外層是否攔截。
看著這里我有幾個疑問:
(1).為什么父類不能攔截Down事件阔馋,requestDisallowInterceptTouchEvent方法是如何工作玛荞?
我們看下ViewGroup中dispatchTouchEvent的源碼
ViewGroup.dispatchTouchEvent

紅色字體就是子view通過requestDisallowInterceptTouchEvent方法設(shè)置的標(biāo)志位。
如果ViewGroup攔截了Down事件呕寝,那么move事件傳遞時勋眯,actionMasked != down && mFirstTouchTarget == null,因此此時便不會去訪問標(biāo)志位,那么我們在子View進行攔截也就失去了作用客蹋。此時塞蹭,若我們需要ViewGroup攔截Move事件,我們變設(shè)置requestDisallowInterceptTouchEvent(false)讶坯,此時disallowIntercept == false番电,便會調(diào)用ViewGroup的onInterceptTouchEvent(ev),因此我們需要在onInterceptTouchEvent返回true來進行攔截辆琅,故除去down事件外應(yīng)返回false漱办。
(2)為什么子View要在dispatchTouchEvent進行攔截呢,為什么不在onInterceptTouchEvent進行攔截呢婉烟?
因為View沒有OnInterceptTouchEvent函數(shù)娩井,只能在此方法攔截。
(3) 為什么我們平時使用requestDisallowInterceptTouchEvent()方法時隅很,我們并沒有重寫外部View撞牢,但是依然可以工作呢?
我們平時使用該方法時一般都是重寫子View在子View中控制叔营,而我們的外部View一般都是ScrollView、RecyclerView所宰、ViewPager等這種可以滑動的控件绒尊,而這些控件已經(jīng)幫我們實現(xiàn)了,他們都是默認不攔截down事件仔粥,攔截move事件的。下面簡單看下ScrollView的代碼。

     @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
     
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_MOVE: {           
                if (yDiff > mTouchSlop && (getNestedScrollAxes() & SCROLL_AXIS_VERTICAL) == 0) {
                    //此處開始滑動癣缅,開始攔截
                    mIsBeingDragged = true;
                    mLastMotionY = y;
                    initVelocityTrackerIfNotExists();
                    mVelocityTracker.addMovement(ev);
                    mNestedYOffset = 0;
                    if (mScrollStrictSpan == null) {
                        mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
                    }
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                }
                break;
            }
          //默認mIsBeingDragged = false
            case MotionEvent.ACTION_DOWN: {
                final int y = (int) ev.getY();
                if (!inChild((int) ev.getX(), (int) y)) {
                    mIsBeingDragged = false;
                    recycleVelocityTracker();
                    break;
                }
           
                mLastMotionY = y;
                mActivePointerId = ev.getPointerId(0);

                initOrResetVelocityTracker();
                mVelocityTracker.addMovement(ev);
               
                mScroller.computeScrollOffset();
                mIsBeingDragged = !mScroller.isFinished();
                if (mIsBeingDragged && mScrollStrictSpan == null) {
                    mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
                }
                startNestedScroll(SCROLL_AXIS_VERTICAL);
                break;
            }

         return mIsBeingDragged;
    }

(4)由于事件傳遞是由ViewGroup傳入View安聘,因此該方法的攔截后第一個move會不會依然傳給view呢?


image.png

image.png

結(jié)果是會的麦向,log與流程圖均獻上瘟裸,有興趣可以看下。
android源碼中使用外部攔截法的較多诵竭,比如RecyclerView和ViewPager话告,在它們的onInterceptTouchEvent的Move事件中均可看出。
3.實例
此時若讓我們使用外部攔截法實現(xiàn)卵慰,開始View向下移動100dp沙郭,然后ViewGroup向下移動的場景呢?


外部攔截法實例

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末裳朋,一起剝皮案震驚了整個濱河市病线,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖送挑,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绑莺,死亡現(xiàn)場離奇詭異,居然都是意外死亡让虐,警方通過查閱死者的電腦和手機紊撕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赡突,“玉大人对扶,你說我怎么就攤上這事〔宴郑” “怎么了浪南?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長漱受。 經(jīng)常有香客問我络凿,道長,這世上最難降的妖魔是什么昂羡? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任絮记,我火速辦了婚禮,結(jié)果婚禮上虐先,老公的妹妹穿的比我還像新娘怨愤。我一直安慰自己,他們只是感情好蛹批,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布撰洗。 她就那樣靜靜地躺著,像睡著了一般腐芍。 火紅的嫁衣襯著肌膚如雪差导。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天猪勇,我揣著相機與錄音设褐,去河邊找鬼。 笑死埠对,一個胖子當(dāng)著我的面吹牛络断,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播项玛,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼貌笨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了襟沮?” 一聲冷哼從身側(cè)響起锥惋,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤昌腰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后膀跌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遭商,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年捅伤,在試婚紗的時候發(fā)現(xiàn)自己被綠了劫流。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡丛忆,死狀恐怖祠汇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情熄诡,我是刑警寧澤可很,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站凰浮,受9級特大地震影響我抠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜袜茧,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一菜拓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧笛厦,春花似錦尘惧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啥么。三九已至登舞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悬荣,已是汗流浹背菠秒。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留氯迂,地道東北人践叠。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像嚼蚀,于是被迫代替她去往敵國和親禁灼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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