2014-01-23 29 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);