開發(fā)筆記之打造通用下拉刷新(重難點篇)

開發(fā)筆記之打造通用下拉刷新(介紹篇)
開發(fā)筆記之打造通用下拉刷新(細(xì)節(jié)篇)
開發(fā)筆記之打造通用下拉刷新(重難點篇)

本篇不講總體實現(xiàn)思路和每一個細(xì)節(jié),只講一下實現(xiàn)過程中遇到的幾個關(guān)鍵問題,雖然叫重難點渊抄,但也并不是什么高級復(fù)雜的技術(shù)秧荆,只是一些實現(xiàn)過程中遇到的問題并且通過不斷思考和嘗試之后才得到的結(jié)果。

一、在哪里實現(xiàn)事件處理邏輯

我們知道,安卓給我們提供了三個事件處理的方法:onTouchEvent、onInterceptTouchEvent劫拢、dispatchTouchEvent肉津。一般我們自定義控件的時候,事件的攔截有兩種思路(來自《android 開發(fā)藝術(shù)探索》):

  • 外部攔截法舱沧,點擊事件先經(jīng)過父容器判斷妹沙,如果父容器需要此事件就攔截,否不攔截熟吏,這種方法比較符合點擊事件的分發(fā)機(jī)制距糖。此方法需要重寫父容器的onInterceptTouchEvent方法,攔截事件后在onTouchEvent方法中寫控件邏輯.
  • 內(nèi)部攔截法牵寺,父容器不攔截任何事件悍引,所有的事件都傳遞給子元素,如果子元素需要此事件就消耗掉帽氓,否則就交給父容器去處理趣斤,這種方法和android中的事件分發(fā)機(jī)制不一致,需要配合requestDisallwInterceptTouchEvent方法才能正常工作黎休,需要子元素重寫dispatchTouchEvent方法浓领。

現(xiàn)在來考慮ptrLayout的實現(xiàn),內(nèi)部攔截法對子元素有特定的要求势腮,需要上下配合联贩,不符合我們的要求,因為ptrLayout不知道也不應(yīng)該知道子view的具體實現(xiàn)捎拯。再看外部攔截法泪幌,在onInterceptTouchEvent方法中攔截事件,同樣不符合ptrLayout的要求玄渗,原因如下:

  1. 我們在acton_down的時候是無法判斷事件是否要攔截或消費(fèi)的座菠,需要通過action_move計算方向才能決定,但是如果沒有view消費(fèi)down藤树,那就不會有后續(xù)的move,那就無從談攔截的事了拓萌。
  2. 父容器一旦攔截了某個move事件岁钓,從此以后子view再也無法收到任何事件了,無法實現(xiàn)我在細(xì)節(jié)篇提到的下拉與子view滑動的銜接

那么在ptrLayout是如何控制事件呢微王?——所有的邏輯都在dispatchTouchEvent中實現(xiàn)屡限。ptrLayout重寫了dispatchTouchEvent方法,在這個方法中炕倘,如果希望子元素接收到事件钧大,則調(diào)用 super.dispatchTouchEvent(),否則不調(diào)用罩旋。這樣一來就可以靈活地控制事件的傳遞啊央。另外眶诈,為了防止沒有view消費(fèi)down事件從而無法接收后續(xù)的move事件,任何時候都要在dispatchTouchEvent方法的down事件中返回true瓜饥。

二逝撬、子view按下效果的取消

在上一節(jié)提到過,手指按下的時候無法判斷是否要攔截事件乓土,所以action_down是一定會傳到子view宪潮,如果子view是listview或者button等控件,就會出現(xiàn)被按下的效果(比如顏色加深趣苏、5.0的ripple波紋)狡相,如果隨后的move事件被ptrLayout攔截了,那么子view的按下效果是不會消失的食磕,會一直顯示著被按住狀態(tài)尽棕。如圖

不處理按下效果.gif

那么為什么我們平時用onInterceptTouchEvent攔截事件的時候不會有這樣的問題呢?原因就是如果父容器攔截了事件芬为,那么其子view就會收到一個action_cancel事件萄金,從而讓子view知道事件被攔截了,取消當(dāng)前的效果媚朦。既然知道了原因氧敢,那么解決辦法自然就出來了,那就是在我們攔截的時候询张,自己手動向下發(fā)一個acion_cancel事件孙乖,主要的代碼是這樣的:

public boolean dispatchTouchEvent(MotionEvent ev)
{
    switch (ev.getAction())
    {
        ...
        case ACTION_MOVE:
            if(需要攔截并通知下層取消事件)
            {
               //構(gòu)造一個cancel事件,其他參數(shù)與當(dāng)前事件一致
                MotionEvent cancelEvent = MotionEvent.obtain(ev.getDownTime(), ev.getEventTime() + ViewConfiguration.getLongPressTimeout(), MotionEvent.ACTION_CANCEL, ev.getX(), ev.getY(), ev.getMetaState());
                super.dispatchTouchEvent(cancelEvent);
             }
    }
    ...
}

這樣一來份氧,子view的問題就可以解決了唯袄。當(dāng)然,我們應(yīng)該控制cancel事件只向下發(fā)一次蜗帜,就是剛開始攔截的那一次恋拷,之后就不用再發(fā)了,以免無謂的方法調(diào)用浪費(fèi)運(yùn)算資源厅缺。

三蔬顾、下拉與子view滑動的銜接

這個點已經(jīng)提到過兩次了(具體效果看細(xì)節(jié)篇),前面的dispatchTouchEvent的重寫就是為了實現(xiàn)這一特性湘捎。首先我們應(yīng)該要清楚诀豁,ptrLayout什么時候該攔截事件,什么時候該傳遞事件窥妇,然后用第一節(jié)說的方法去攔截和傳遞就可以了舷胜。關(guān)于判斷攔截條件這一點,涉及到的條件判斷太多了活翩,這里不一一細(xì)說烹骨,有興趣可以看具體的代碼翻伺,里面有各種注釋,代碼比文字更容易明白展氓。這里只說一種情況穆趴,又是需要手動發(fā)事件才能解決的。文字描述比較乏力遇汞,看圖

開始.png
滑動.png
隱藏.png

子view在Y1處收到down事件到在Y2處收到move事件未妹。從上一節(jié)我們知道,子view在收到down事件后會馬上收到一個cancel事件空入,然后再收到move事件络它,也就是等于子view直接收到move事件的,這時子view可能有兩種處理方法:

  1. 直接忽略這些Move事件歪赢,因為沒有收到down事件化戳,無法判斷滑動的距離。這是大部分滑動控件的做法埋凯。忽略move事件点楼,就意味著整個滑動沒有銜接起來。
  2. 處理move事件白对,按上一次的down事件的位置來計算滑動的距離掠廓,但是由于Y2到Y(jié)1是有一定的距離的,子view會在一瞬間滑動Y1-Y2的距離甩恼,雖然滑動銜接起來了蟀瞧,還是畫面沒有銜接起來。

這里解決辦法的思路和第二節(jié)一樣条摸,既然缺一個action_down事件悦污,那么我們就手動發(fā)一個就可以了,發(fā)的時機(jī)就是手指剛到達(dá)Y2的時候钉蒲。代碼大概是這樣的:

public boolean dispatchTouchEvent(MotionEvent ev)
{
    switch (ev.getAction())
    {
        ...
        case ACTION_MOVE:
            if(不再攔截move事件)
            {
               if(還沒發(fā)送down事件)
               {
                   //構(gòu)造一個down事件切端,其他參數(shù)與當(dāng)前事件一致
                    MotionEvent downEvent = MotionEvent.obtain(ev.getDownTime(), ev.getEventTime() + ViewConfiguration.getLongPressTimeout(), MotionEvent.ACTION_Down, ev.getX(), ev.getY(), ev.getMetaState());
                    return super.dispatchTouchEvent(downEvent);
               }
               }else//已經(jīng)發(fā)送過down事件了,直接向下傳遞move事件
               {
                    return super.dispatchTouchEvent(ev);
               } 
           }
    }
    ...
}

四、橫向滑動處理

當(dāng)我們的子view存在橫向滑動的時候顷啼,比如viewPager帆赢,我們就需要考慮橫向滑動的處理了。首先线梗,并不是任何時候子view都可以橫向滑動的,所以設(shè)置一個mHasHorizontalChild變量怠益,當(dāng)這個功能開啟的時候才會去考慮橫向的處理仪搔。
  我們怎么判斷滑動是橫向的還是縱向的呢?這是一個簡單的幾何數(shù)學(xué)題,無非就是計算滑動前后兩個點的連線的斜率蜻牢,k = ΔY / ΔX, 我們可以簡單地認(rèn)為當(dāng)k大于1時為縱向烤咧,小于1時為橫向(當(dāng)然這個1可以是其他值偏陪,可以根據(jù)橫縱向的靈敏度來設(shè)置)。但是煮嫌,考慮到實現(xiàn)的使用體驗笛谦,當(dāng)我們手指開始橫向滑動時就不太可能想要下拉刷新了,意思是昌阿,當(dāng)手指橫向滑動了一段距離饥脑,手指突然向下移動,也不應(yīng)該去觸發(fā)下拉的邏輯懦冰,不然子view向右滑動到一半然后下拉灶轰,頭部顯示出來就會變得十分奇怪,反之亦然刷钢。

橫向處理.gif

這里只是一個細(xì)節(jié)問題笋颤,實現(xiàn)的方法很簡單,開始滑動時判斷當(dāng)前的滑動方向内地,就記住當(dāng)前的判斷結(jié)果伴澄,以后就按照這個結(jié)果來處理事件,直到下一次的滑動阱缓,這里就不再多講非凌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市茬祷,隨后出現(xiàn)的幾起案子清焕,更是在濱河造成了極大的恐慌,老刑警劉巖祭犯,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秸妥,死亡現(xiàn)場離奇詭異,居然都是意外死亡沃粗,警方通過查閱死者的電腦和手機(jī)粥惧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來最盅,“玉大人突雪,你說我怎么就攤上這事∥屑” “怎么了咏删?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長问词。 經(jīng)常有香客問我督函,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任辰狡,我火速辦了婚禮锋叨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宛篇。我一直安慰自己娃磺,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布叫倍。 她就那樣靜靜地躺著偷卧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪段标。 梳的紋絲不亂的頭發(fā)上涯冠,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天,我揣著相機(jī)與錄音逼庞,去河邊找鬼蛇更。 笑死,一個胖子當(dāng)著我的面吹牛赛糟,可吹牛的內(nèi)容都是我干的派任。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼璧南,長吁一口氣:“原來是場噩夢啊……” “哼掌逛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起司倚,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤豆混,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后动知,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體皿伺,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年盒粮,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸵鸥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡丹皱,死狀恐怖妒穴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情摊崭,我是刑警寧澤讼油,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站呢簸,受9級特大地震影響汁讼,放射性物質(zhì)發(fā)生泄漏淆攻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一嘿架、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啸箫,春花似錦耸彪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扎唾,卻和暖如春召川,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胸遇。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工荧呐, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纸镊。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓倍阐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親逗威。 傳聞我的和親對象是個殘疾皇子峰搪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

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