【问题标题】:Dispatch event from Scrollview to underlaying Viewpager从 Scrollview 调度事件到底层 Viewpager
【发布时间】:2014-02-14 09:48:10
【问题描述】:

在我的 Android 应用中,我有以下布局:

<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。

关于如何解决这个问题的任何想法?

【问题讨论】:

    标签: android touch scrollview android-custom-view android-event


    【解决方案1】:

    对于对此问题的答案感兴趣或有类似问题的任何人,这是我的解决方法。

    首先,一般的方法是制作一个自定义视图,拦截某些触摸事件并将它们委托给正确的孩子。

    在我的例子中,viewpager 应该拦截水平手势,而 位于 viewpager 顶部 的滚动视图应该只获得垂直滚动事件。 对我来说,一个特殊的要求是,viewpager 也应该只拦截特定范围内的触摸事件,即一个虚拟视口,它是 inside 覆盖滚动视图的子视图。

    在自定义布局类中,必须重写 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事件。

    从我的 Activity 代码中,我只是设置了调度目标和委托视图:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多