Android 開發實踐 ViewGroup 實現左右滑出視窗(二)

來源:互聯網
上載者:User

接上一篇

<Android 開發實踐 ViewGroup 實現左右滑出視窗(一)http://www.cnblogs.com/inkheart0124/p/3532862.html>

 源碼: http://files.cnblogs.com/inkheart0124/PushSlider.zip

ViewGroup中touch事件的處理,有三個函數

public boolean dispatchTouchEvent(MotionEvent ev);事件派發

public boolean onInterceptTouchEvent(MotionEvent ev);事件攔截

public boolean onTouchEvent(MotionEvent ev);事件處理

(廢話一句,View中只有兩個,dispatchTouchEvent和onTouchEvent,ViewGroup繼承了View以後增加了onInterceptTouchEvent)

 

一次完整的touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE....->ACTION_UP

其中對ACTION_DOWN的處理傳回值比較重要,如果dispatchTouchEvent時返回false,那表示這一次touch事件我都不需要,之後的move和up都不會再傳給我的ViewGroup。

 

 action ==((gdHandled) && (action == + action +   + action +  action ==((gdHandled) && (action == + action +   + action +  action = 

重寫這三個函數,先把event直接丟給mGDetector處理,然後在調用系統的派發機制把訊息傳遞到子View。

注意Down訊息一定不能攔截,ViewGroup主要根據move和up的情況來區別手勢,當收到down訊息的時候,我們還不能確定使用者是要滑動呢還是要操作子view中的控制項。Down訊息如果被攔截,意味著這一個訊息組都不會再傳給子view。

 

onTouchEvent中什麼都沒做,直接返回了true,這個方法會在dispatchTouchEvent函數調用super.dispatchTouchEvent(ev)時跑到,它的傳回值就是super.dispatchTouchEvent(ev)的傳回值,這裡至少在down訊息的時候必須返回true,否則就像前面說的那樣,整組訊息都不會再傳遞給我的pushslider了。

 

手勢:

PushSlider類實現了android.view.GestureDetector.OnGestureListener介面,在前一篇的建構函式中我們建立了一個手勢對象,並註冊監聽。

mGDetector =  GestureDetector(mContext,);

下面就要實現OnGestureListener中的方法

public boolean onDown(MotionEvent ev);處理down訊息

public void onLongPress(MotionEvent arg0);長按

public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);拖動,收到move訊息時會跑到

public boolean onFling(MotionEvent eDown, MotionEvent eMove, float velocityX,float velocityY);快速滑拋

public void onShowPress(MotionEvent arg0);發生down訊息後,用來顯示高亮等可視化的處理

public boolean onSingleTapUp(MotionEvent ev);處理一次輕觸

詳細的解釋就不寫了,android developer官網上解釋的很詳細。這裡我只需要處理onFling和onSingleTapUp,onScroll的代碼後來沒用,屏蔽掉了。

 

onFling 是發生donw-move-move....-up時,最後up事件時會調用到,根據入參float velocityX和float velocityY這兩個速度值,決定這是不是我們想要的一次滑拋手勢

  boolean onFling(MotionEvent eDown, MotionEvent eMove, velocityX,     log( + eDown.getX() +  + eMove.getX() + +           ((eDown.getX() - eMove.getX() > FLING_DISTANCE*mDensity) && (Math.abs(velocityX)>                      flingTo(MOVE_FLAG_ALLOW_LEFT,             log(                                   ((eMove.getX() - eDown.getX() > FLING_DISTANCE*mDensity) && (Math.abs(velocityX)>                      flingTo(MOVE_FLAG_ALLOW_RIGHT,             log(                     log(       }

5~11行,手勢是從右向左 <<<--

14~20行,手勢是從左向右 -->>>

根據eMove和eDown的相對位移,及X方向的速度,判斷是否滑到下一頁。

 

onSingleTapUp 是發生down-up這樣的一次點擊(輕觸)時調用

       Rect focusRect =        x =      left = focusRect.left-      right = focusRect.right-              ((x < left) &&         flingTo(MOVE_FLAG_ALLOW_RIGHT,         log(               } ((x > right) &&         flingTo(MOVE_FLAG_ALLOW_LEFT,         log(                log(              }

3,4行,取得當前focus的子view的地區;

6,7行,這裡取到的HitRect是相對與viewgroup的0,0點的相對座標。需要換算成實際座標,mScroller.getCurrX()是viewgroup的x位置相對於螢幕原點的值。

由於我有一個滑出子view是半屏的,當這個半屏的設定菜單被喚出後,我希望輕觸一下菜單以外的地區 就可以關閉菜單回到主介面。重寫onSingleTapUp方法就是為了處理這種情況。

 

flingTo,關於實現滑動,其實有很多方法,最直觀的就像我們在onLayout中做的那樣,重新算好每個子View的位置,然後layout一遍。

但我覺得用view自己的Scroller類是最簡單最省心的。

   flingTo(                     startX =      endX=           (direct ==         focusedIndex ++          (focusedIndex ==             endX =           (focusedIndex ==             endX =          dx = endX -         mScroller.startScroll(startX, , dx, ,(fast?:     }         focusedIndex --         (focusedIndex ==             endX =           (focusedIndex ==             endX =          dx = endX -         mScroller.startScroll(startX, , dx, ,(fast?:      log( +   }

5行,startx,得到當前ViewGroup的位置(相對於螢幕原點);

10~15行,切換焦點,根據新的焦點得到endX,及滑動後ViewGroup的位置;

18行,直接調用Scroller的startScroll方法,就開始滑動了,很簡單吧!

 

startScroll原型:public void startScroll(int startX, int startY, int dx, int dy, int duration)

5個入參意義一目瞭然。

 

flingTo函數的兩個入參 direct是滑動方向,還有一個boolean fast,表示滑動速度,用它來確定startScroll的duration,100和250是實測的經驗值。

當滑拋手勢喚出或關閉半屏菜單時,fast=false。讓使用者看到一個清晰的滑動過程。

當使用者按menu或cancel鍵的時候,fast=true。快速喚出或關閉介面。

 

menu鍵和canel鍵的處理,我沒有把它們定義在PushSlider的管理範疇內。這兩個索引值仍然是有activity處理,PushSlider只需要給出一個public的方法。

簡單的說,PushSlider就管自己的3個子View,他們的顯示,位置,滑動,焦點。具體功能上的東東全都是activity的活。

因此PushSlider除了讓activity監聽焦點變化外(見上一篇),還需要提供一些查詢和操作介面,比如查詢當前焦點,查詢當前是否處於滑動中。

比較重要的操作有兩個:

public void pushForbid(boolean forbid){
  mForbidden = forbid;
 }

某些情況下,activity可能想不讓使用者滑動切換焦點,就可以pushForbid。

 

另一個public void moveToPageById(int index),activity可直達某個子View,比如前面提到的 按menu鍵喚出設定菜單的子View。

具體代碼不貼了,仍然是調用flingTo(fast)的模式。

 

PushSlider搞定了,看一下activity中怎麼用它。

layout/main.xml

                                                                                                                                      

6~15行,加入PushSlider,插入三個子View,分別是

 

                     mPushView =      screenWidth =     mPushView.setPageWidth(PushSlider.SLIDER_PAGE_LEFT, screenWidth/2      mPushView.setOnPageChangedListener(             } 

5行,把main.xml設為contect view;

7~13行,獲得PushSlider物件控點,設定左右兩個view的寬度,設定焦點切換監聽。


oh~~~ 全篇完~~

新年攢人品,稍後發源碼,還不知道怎麼上傳源碼呢

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.