问题
My setup is simple enough:
<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>
The content of onCreate()
:
layoutManager = new LinearLayoutManager( this );
layoutManager.setOrientation( LinearLayoutManager.HORIZONTAL );
topTopicRecyclerView.setLayoutManager( layoutManager );
Now, when I swipe the recyclerView left or right and the swipe angle is not perfectly horizontal, the SwipeRefreshLayout jumps in and takes over the scrolling control. That leads to annoying visual "hiccups" inside the recyclerView.
If the SwipeRefreshLayout is disabled, all is fine.
So, how can I deactivate the SwipeRefreshLayout's scrolling control over the RecyclerView's area?
回答1:
As per this discussion about SRL and HorizontalScrollView, I created the counterpart for the 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 );
}
}
and usage in XML:
<com.commons.android.OnlyVerticalSwipeRefreshLayout
android:id="@+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<tags/>
</com.commons.android.OnlyVerticalSwipeRefreshLayout>
回答2:
I get some code from net.
Change scrollView
to Special 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);
}
}
Or change RecyclerView
to 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;
}
}
来源:https://stackoverflow.com/questions/34136178/swiperefreshlayout-blocking-horizontally-scrolled-recyclerview