【问题标题】:Disable vertical swipe (SwipeRefreshLayout) when swiping in a horizontal Listview在水平 Listview 中滑动时禁用垂直滑动 (SwipeRefreshLayout)
【发布时间】:2014-10-06 14:10:56
【问题描述】:

我的应用目前由一个ViewPager 组成,其中有几个Fragments。在特定的Fragment 中,我有一个SwipeRefreshLayout 和一个ScrollView,并在这个容器中,一个TwoWayView 类型的Horizo​​talListView。

问题是当我在ListView 中水平滑动时,SwipeRefreshLayout 的垂直滚动未被禁用,有时它会在操作过程中中断水平滑动。

这是我试图解决的问题:

horizListView.setOnTouchListener(new ListView.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                // Disallow ScrollView to intercept touch events.
                mSwipeRefreshLayout.requestDisallowInterceptTouchEvent(true);
                v.getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_UP:
                // Allow ScrollView to intercept touch events.
                mSwipeRefreshLayout.requestDisallowInterceptTouchEvent(false);
                v.getParent().requestDisallowInterceptTouchEvent(false);
                break;
        }

        // Handle HorizontalScrollView touch events.
        v.onTouchEvent(event);
        return true;
    }
});

这是我的布局:

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
            <LinearLayout
                android:layout_width="match_parent"
                android:orientation="vertical"
                android:layout_height="match_parent">

                <TextView
                    android:id="@+id/tv_info1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:padding="10dp"
                    android:textStyle="bold"
                    android:textSize="@dimen/text_medium"
                    android:textColor="@color/light_gray"
                    android:text="@string/place_proposal" />

                <org.lucasr.twowayview.TwoWayView
                    android:orientation="horizontal"
                    android:id="@+id/horizlistview"
                    android:layout_height="230dp"
                    android:scaleType="centerCrop"
                    android:drawSelectorOnTop="false"
                    android:layout_width="fill_parent" />

                <TextView
                    android:id="@+id/tv_info2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textColor="@color/light_gray"
                    android:textSize="@dimen/text_medium"
                    android:textStyle="bold"
                    android:padding="10dp"
                    android:text="@string/actual_position"
                    android:paddingTop="5dp" />

                <ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
                    android:id="@+id/vf"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content">

                    <include
                        android:id="@+id/include_w"
                        layout="@layout/include_wicard_homescreen" />

                    <include
                        android:id="@+id/include_no_w"
                        layout="@layout/include_no_wicard" />

                </ViewFlipper>

            </LinearLayout>
    </ScrollView>

</android.support.v4.widget.SwipeRefreshLayout>

如果有人可以帮助我,那就太好了。

【问题讨论】:

  • 尝试删除v.onTouchEvent(event);并返回false而不是true
  • 我刚试了,但是不行
  • 你应该做一个自定义的滑动刷新布局,试试这个,click here

标签: android android-viewpager swipe horizontalscrollview swiperefreshlayout


【解决方案1】:

覆盖 SwipeRefreshLayout。这是我的代码,它工作正常:

public class RefreshLayoutExIntercepter extends SwipeRefreshLayout {

public RefreshLayoutExIntercepter(Context ctx) {
    super(ctx);
    mTouchSlop = ViewConfiguration.get(ctx).getScaledTouchSlop();
}

public RefreshLayoutExIntercepter(Context ctx, AttributeSet attrs) {
    super(ctx, attrs);
    mTouchSlop = ViewConfiguration.get(ctx).getScaledTouchSlop();
}

private int mTouchSlop;
private float mPrevX;

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        mPrevX = event.getX();
        break;

    case MotionEvent.ACTION_MOVE:
        final float eventX = event.getX();
        float xDiff = Math.abs(eventX - mPrevX);

        if (xDiff > mTouchSlop) {
            return false;
        }
    }

    return super.onInterceptTouchEvent(event);
}
}

【讨论】:

    【解决方案2】:

    我在 SwipeRefreshLayout 拦截触摸事件时遇到了类似的问题。在最新的支持库(我使用的是 25.3.1 atm)中,无需扩展 SwipeRefreshLayout 即可解决此问题。我是这样做的:

    1. 应该接收触摸事件的视图必须isNestedScrollingEnabled() 中返回 true。
    2. 您的触摸监听器必须onTouchEvent() 中为 ACTION_DOWN 事件返回 true。否则,具有此指针 id 的事件将由 SwipeRefreshLayout 处理。
    3. 您的触摸侦听器必须onTouchEvent() 中返回 true,以便您使用视图处理所有操作。
    4. 使用requestDisallowInterceptTouchEvent(bool) 关闭/打开 SwipeRefreshLayout 及其父级(如果有)的触摸灵敏度。

    在 OP 的情况下,设置 RecyclerView.setNestedScrollingEnabled(true); 应该可以解决问题。

    这是我的自定义视图代码示例。使用此视图时,我可以通过水平滑动来更改选项卡,并在视图一直向上滚动时享受 SwipeRefreshLayout 的功能。此视图使用所有其他垂直滚动。希望对你有帮助。

    public void CustomScrollableView extends View {
    private final GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
    
        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }
    
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            // Check if view is zoomed.
            if (mIsZooming)
                return true;
    
            if (Math.abs(distanceY) < Math.abs(distanceX)) return false; // horizontal scrolling
    
            // Calculate the new origin after scroll.
            mYOffset -= distanceY;
            ViewCompat.postInvalidateOnAnimation(CustomScrollableView.this);
            return mYOffset < 0;
        }
    }
    
    private void blockParentScrolling(final boolean block) {
        final ViewParent parent = getParent();
        if (parent != null) {
            parent.requestDisallowInterceptTouchEvent(block);
        }
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean consumedByGestureDetector = mGestureDetector.onTouchEvent(event);
        blockParentScrolling(consumedByGestureDetector);
        return consumedByGestureDetector;
    }
    
    @Override
    public boolean isNestedScrollingEnabled() {
        return true;
    }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-12
      • 2019-12-25
      • 1970-01-01
      • 1970-01-01
      • 2019-05-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多