viewpager與子view的事件沖突解決


  問題:

    對android的事件機制一直不怎么了解,最近android項目中運用viewpager+listview (就是viewpager的子view中嵌套了listview),出現了觸摸手勢沖突

  吐槽:

  問題一來很是捉急,於是執行傻瓜式問題解決,各種谷歌大神求支援,按照網上的解決方案,也不管對不對應我的情況,一頓亂搞....

  顯然無數次失敗之后還是沒給我足夠的教訓,這次結果依然是沒找到現成的,(;一_一) ...

  機制:

    糾結了一天,決定好好理一理android的事件機制,找到下面這3張圖原地址我沒找到,已經在在谷歌大神那留下N個副本..實在沒找到原作者,如有知道原創地址請與我聯系,覺得豁然開朗


       

            圖1                圖2                        圖3


  onInterceptTouchEvent 和 onTouchEvent 清楚了,還有個 dispatchTouchEvent 不太清楚,網上說是分發事件的,在調試時,我發現 viewgroup 的分發機制似乎不同(dispatchTouchEvent在onInterceptTouchEvent后調用)。

  最終找到這篇文章 "Android事件處理第一節(View對Touch事件的處理)",看到其中 View.dispatchTouchEvent() 的源碼,又是豁然開朗.

    public boolean dispatchTouchEvent(MotionEvent event) 
    {  
        if (mInputEventConsistencyVerifier != null) 
        {  
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);  
        }  
  
        if (onFilterTouchEventForSecurity(event)) 
        {  
            //noinspection SimplifiableIfStatement  
            ListenerInfo li = mListenerInfo;  
            if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED  
                    && li.mOnTouchListener.onTouch(this, event))
            {  
                return true;  
            }  
  
            if (onTouchEvent(event)) 
            {  
                return true;  
            }  
        }  
  
        if (mInputEventConsistencyVerifier != null)
        {  
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);  
        }  
        return false;  
    } 

  也就是說是 dispatchTouchEvent 在調用 onTouchEvent 。

  思路:

      最終效果是豎直方向滑動時listview動起來,水平方向滑動viewpager動起來,顯然我需要對滑動手勢進行判斷,

      

     (1)  在 case MotionEvent.ACTION_DOWN: 分支獲取第一次按下點的坐標
    
     (2)  在 case MotionEvent.ACTION_MOVE: 分支獲取移動結束點的坐標

     (3)  通過兩點橫坐標差值與豎坐標的差值可以判斷手勢方向;

      這里我的view層次是,activity->viewpager->listview.

      所以我希望它的事件流向像下圖一樣


 

      


 

      思路差不多就這些.

   解決:

      直接上代碼吧.

/*  代碼位置:最頂層的VIEW,(viewpager的子view)  */

private float xDistance, yDistance, xLast, yLast; /* (non-Javadoc) * @see android.widget.AbsListView#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //獲取第一次按下點的坐標 xDistance = yDistance = 0f; xLast = ev.getX(); yLast = ev.getY(); break; case MotionEvent.ACTION_MOVE:        //獲取移動結束點的坐標  final float curX = ev.getX(); final float curY = ev.getY();
       //差值 xDistance
+= Math.abs(curX - xLast); yDistance += Math.abs(curY - yLast); xLast = curX; yLast = curY; if(xDistance <= yDistance) return super.onTouchEvent(ev); // 消耗 else return false; // 往下傳遞 } return super.onTouchEvent(ev); }

      如果你的項目,viewpager之下還有 view ,並且還有手勢處理,那你可以對你想屏蔽的 view 使用 requestDisallowInterceptTouchEvent(true); ,比如說我這的Activity還有手勢處理,我想屏蔽它,於是就在 viewpager 的 onInterceptTouchEvent 里調用了 getParent().requestDisallowInterceptTouchEvent(true); ,代碼如下

  @Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) 
    {
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.onInterceptTouchEvent(arg0);
    }

      問題解決,暫時就這些了.

      

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM