Reputation: 331
My app is currently composed by a ViewPager
that have several Fragments
. In a specific Fragment
I have a SwipeRefreshLayout
with a ScrollView
and into this container, a HorizotalListView of type TwoWayView
.
The problem is when i swipe horizontally in the ListView
the vertical scroll for the SwipeRefreshLayout
isn't disabled and sometimes it breaks the horizontal swipe during the action.
This is what I tried to do to resolve it:
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;
}
});
And here is my layout:
<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>
If anyone can help me it would be great.
Upvotes: 1
Views: 3544
Reputation: 1395
I had a similar problem with SwipeRefreshLayout intercepting touch events. In latest support library (i am using 25.3.1 atm) this can be dealt with without extending SwipeRefreshLayout. Here's how i did it:
isNestedScrollingEnabled()
.onTouchEvent()
for ACTION_DOWN events. Otherwise the events with this pointer id will be handled by SwipeRefreshLayout.onTouchEvent()
for all the actions you want to handle with your view.requestDisallowInterceptTouchEvent(bool)
to turn off/on touch sensivity of SwipeRefreshLayout and its parents if any.In OP's case setting RecyclerView.setNestedScrollingEnabled(true);
should solve the issue.
Here's a sample of my custom view's code. When Using this view, i can change tabs by swiping horizontally and enjoy the functionality of SwipeRefreshLayout when the view is scrolled all the way up. All other vertical scrolling is consumed by this view. I hope it helps.
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;
}
}
Upvotes: 0
Reputation: 11
Override SwipeRefreshLayout. And here is my code, it works fine:
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);
}
}
Upvotes: 1