SwipeRefreshLayout阻塞了横向滚动的RecyclerView

8

我的设置相当简单:

<android.support.v4.widget.SwipeRefreshLayout
     android:id="@+id/swiperefresh"
     android:layout_width="match_parent"
     android:layout_height="match_parent" >

     <android.support.v7.widget.RecyclerView
         android:id="@+id/recyclerView"
         android:layout_width="match_parent"
         android:layout_height="220dp"/>

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

onCreate()的内容:

layoutManager = new LinearLayoutManager( this );
layoutManager.setOrientation( LinearLayoutManager.HORIZONTAL );
topTopicRecyclerView.setLayoutManager( layoutManager );

现在,当我向左或向右滑动recyclerView并且滑动角度不是完美水平时,SwipeRefreshLayout会跳入并控制滚动。这会导致recyclerView内部出现令人讨厌的视觉“抽搐”。

如果禁用SwipeRefreshLayout,则一切正常。

那么,我如何取消SwipeRefreshLayout对RecyclerView区域的滚动控制?


1
不建议使用两个嵌套滚动条。尽量只使用一个滚动方向。 - Nanoc
4个回答

27
根据关于SRL和HorizontalScrollView的这个讨论,我为SwipeRefreshLayout创建了对应的对应物。
public class OnlyVerticalSwipeRefreshLayout extends SwipeRefreshLayout {

  private int touchSlop;
  private float prevX;
  private boolean declined;

  public OnlyVerticalSwipeRefreshLayout( Context context, AttributeSet attrs ) {
    super( context, attrs );
    touchSlop = ViewConfiguration.get( context ).getScaledTouchSlop();
  }

  @Override
  public boolean onInterceptTouchEvent( MotionEvent event ) {
    switch( event.getAction() ){
      case MotionEvent.ACTION_DOWN:
        prevX = MotionEvent.obtain( event ).getX();
        declined = false; // New action
        break;

      case MotionEvent.ACTION_MOVE:
        final float eventX = event.getX();
        float xDiff = Math.abs( eventX - prevX );
        if( declined || xDiff > touchSlop ){
          declined = true; // Memorize
          return false;
        }
        break;
    }
    return super.onInterceptTouchEvent( event );
  }
}

在XML中的使用:

<com.commons.android.OnlyVerticalSwipeRefreshLayout
     android:id="@+id/swiperefresh"
     android:layout_width="match_parent"
     android:layout_height="match_parent" >

   <tags/>

</com.commons.android.OnlyVerticalSwipeRefreshLayout>

8
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            if(newState == SCROLL_STATE_DRAGGING) 
                mSwipeToRefresh.setEnabled(false);

            if(newState == SCROLL_STATE_IDLE) 
                mSwipeToRefresh.setEnabled(true);
        }
    });

0
在 Kotlin 中,您可以在设置 RecyclerView 适配器的位置放置这些行。
 yourRecyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener() {
                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                    super.onScrollStateChanged(recyclerView, newState)
                    if (newState == RecyclerView.SCROLL_STATE_DRAGGING) yourSwipeRefreshLayout.isEnabled =
                        false
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) binding.yourSwipeRefreshLayout.isEnabled =
                        true
                }
            })

-1
我从网络上获取了一些代码。 将scrollView更改为特殊的scrollview
package com.image.indicator.control;  

import android.content.Context;  
import android.util.AttributeSet;  
import android.view.MotionEvent;  
import android.widget.ScrollView;  

/** 


 * @File: ScrollViewExtend.java 

 * @Package com.image.indicator.control 

 * @Author Hanyonglu 

 * @Date 2012-6-18 

 * @Version V1.0 
 */  
public class ScrollViewExtend extends ScrollView {  

    private float xDistance, yDistance, xLast, yLast;  

    public ScrollViewExtend(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  

    @Override  
    public boolean onInterceptTouchEvent(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 false;  
                }    
        }  

        return super.onInterceptTouchEvent(ev);  
    }  
}  

或者将 RecyclerView 改为 ViewPager

public class ChildViewPager extends ViewPager{  
    /** 触摸时按下的点 **/  
    PointF downP = new PointF();  
    /** 触摸时当前的点 **/  
    PointF curP = new PointF();   
    OnSingleTouchListener onSingleTouchListener;  

    public ChildViewPager(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        // TODO Auto-generated constructor stub  
    }  

    public ChildViewPager(Context context) {  
        super(context);  
        // TODO Auto-generated constructor stub  
    }  

    @Override  
    public boolean onInterceptTouchEvent(MotionEvent arg0) {  
        // TODO Auto-generated method stub  
        //当拦截触摸事件到达此位置的时候,返回true,  
        //说明将onTouch拦截在此控件,进而执行此控件的onTouchEvent  
        return true;  
    }  

    @Override  
    public boolean onTouchEvent(MotionEvent arg0) {  
        // TODO Auto-generated method stub  
        //每次进行onTouch事件都记录当前的按下的坐标  
        curP.x = arg0.getX();  
        curP.y = arg0.getY();  

        if(arg0.getAction() == MotionEvent.ACTION_DOWN){  
            //记录按下时候的坐标  
            //切记不可用 downP = curP ,这样在改变curP的时候,downP也会改变  
            downP.x = arg0.getX();  
            downP.y = arg0.getY();  
            //此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰  
            getParent().requestDisallowInterceptTouchEvent(true);  
        }  

        if(arg0.getAction() == MotionEvent.ACTION_MOVE){  
            //此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰  
            getParent().requestDisallowInterceptTouchEvent(true);  
        }  

        if(arg0.getAction() == MotionEvent.ACTION_UP){  
            //在up时判断是否按下和松手的坐标为一个点  
            //如果是一个点,将执行点击事件,这是我自己写的点击事件,而不是onclick  
            if(downP.x==curP.x && downP.y==curP.y){  
                onSingleTouch();  
                return true;  
            }  
        }  

        return super.onTouchEvent(arg0);  
    }  

        /** 
     * 单击 
     */  
    public void onSingleTouch() {  
        if (onSingleTouchListener!= null) {  

            onSingleTouchListener.onSingleTouch();  
        }  
    }  

    /** 
     * 创建点击事件接口 
     * @author wanpg 
     * 
     */  
    public interface OnSingleTouchListener {  
        public void onSingleTouch();  
    }  

    public void setOnSingleTouchListener(OnSingleTouchListener onSingleTouchListener) {  
        this.onSingleTouchListener = onSingleTouchListener;  
    }  

}  

  1. 我没有滚动视图。
  2. 我无法使用ViewPager来展示我的内容。
- injecteer
也许你可以在我的代码中将scrollView替换为SwipeRefresh,或者将viewPager替换为recyclerview。 - tiny sunlight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接