2014-01-23 38 views
2

在我的Android應用程序,我以下佈局:調度事件墊層Viewpager

<CustomRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
> 

<android.support.v4.view.ViewPager 
    android:id="@+id/image_viewpager" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    /> 

<OverScrollBounceScrollView 
    android:id="@+id/scrollview" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fillViewport="true" 
    > 

    <LinearLayout 
     android:id="@+id/user_profile_scroll_content" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical" 
     > 

     <RelativeLayout 
      android:id="@+id/dummy_viewport" 
      android:layout_width="match_parent" 
      android:layout_height="350dp" 
      > 

     </RelativeLayout> 

     <LinearLayout 
      android:id="@+id/scroll_content" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:orientation="vertical" 
      android:background="@android:color/white" 
      > 

      ...some content 

     </LinearLayout> 
    </LinearLayout> 
</OverScrollBounceScrollView> 
</CustomRelativeLayout> 

它看起來這個問題:

http://i.stack.imgur.com/lzL5u.png

我的目標是:

  1. 當我在Y方向上滾動時,我想滾動視圖接管並正常滾動
  2. 當我在X方向的滾動我想滾動視圖下viewpager現在接手

的問題是,滾動視圖通吃事件和viewpager不能在所有的到達。

關於如何解決這個問題的任何想法?

回答

4

對於任何對這個問題的答案感興趣或有類似問題的人,這裏是我如何解決它。

首先,一般的做法是製作一個自定義視圖,用於攔截某些觸摸事件並將它們委託給正確的孩子。

在我的情況下,viewpager應該截取水平手勢,並且viewpager頂層上的滾動視圖應該只能獲得垂直滾動事件。 對我來說,一個特別的要求是viewpager也應該攔截一定範圍內的觸摸事件,即一個虛擬視口,這是一個子視圖裏面的覆蓋滾動視圖。

在自定義佈局類一個具有覆蓋onInterceptTouchEvent()方法與的onTouchEvent()方法相結合:

@Override 
public boolean onInterceptTouchEvent (MotionEvent event) { 
    // 1.) remember DOWN event ALWAYS as this is important start for every gesture 
    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      mInitialX = event.getX(); 
      mInitialY = event.getY(); 
      mInitialDownEvent = MotionEvent.obtainNoHistory(event); 
      mIsDownEventDispatched = false; 
      break; 
     case MotionEvent.ACTION_MOVE: 
      final float x = event.getX(); 
      final float y = event.getY(); 
      final int yDiff = (int) Math.abs(y - mInitialY); 
      final int xDiff = (int) Math.abs(x - mInitialX); 
      calculateDelegatesHitRectangle(); 
      if(xDiff > mTouchSlop && mDelegateBounds.contains((int)event.getX(), (int)event.getY())){ 
       // 2.) if we scroll more in X-direction AND we are within the bounds of our delegatinView 
       //  then INTERCEPT event here, so this views onTouch will be called 
       Log.d("hitrect", "HITRECT--- TOP: " + mDelegateBounds.top + " BOTTOM: " + mDelegateBounds.bottom); 
       return true; 
      } 
      break; 
    } 

    return super.onInterceptTouchEvent(event); 

} 


@Override 
public boolean onTouchEvent(MotionEvent event) { 

    // 3.) we receive ALL following event after X-Scroll has been intercepted 
    //  but the DOWN event was handled by this view so we have to dispatch the remembered down event 
    //  so the dispatch-target has a valid start for the scroll-gesture 
    if(!mIsDownEventDispatched){ 
     mDispatchTargetView.dispatchTouchEvent(mInitialDownEvent); 
     mIsDownEventDispatched = true; 
    } 
    mDispatchTargetView.dispatchTouchEvent(event); 
    Log.d("touch", "ROOT: onTouchEvent after Intercept " + event.getActionMasked()); 
    return true; 
} 

正如你所看到的,我總是檢查並保存DOWN事件在一旦檢測到移動,我檢查它是否在x方向上執行(對於viewpager)。在那時被攔截。我的calculateDelegatesHitRectangle()方法在這種情況下只檢查我是否在範圍內,除了觸摸事件以外我想要的。

在onTouch中,我只將截取的水平手勢重新路由到我的viewpager,它通過setter注入到此自定義視圖中。爲了有一個正確的手勢,我還需要重新路由攔截的DOWN事件。

從我的活動代碼,我剛纔設置的調度目標和委託方的觀點:

dispatchAwareLayout.setDispatchTargetView(mImageViewPager); 
dispatchAwareLayout.setDelegateView(mDummyViewport);