HorizontalScrollView inside SwipeRefreshLayout

I have implemented the new SwipeRefreshLayout component in my application and it works well with any vertical views like ListView , GridView and ScrollView .

This behaves very poorly with horizontal views, such as HorizontalScrollView . When you scroll left or right, the SwipeRefreshLayout caches the touch, prevents it from getting a HorizontalScrollView and starts scrolling vertically to complete the update.

I tried to solve this problem, as I previously solved the problems with the vertical ScrollView with the ViewPager inside using requestDisallowInterceptTouchEvent , but this did not work. I also noticed that this method is overridden in the original SwipeRefreshLayout class without returning super. Instead, Google developer commented " //Nope. " :)

Since the SwipeRefreshLayout component is relatively new, I could not find a solution that fixes the horizontal scroll problem, while allowing me to scroll the image to track and handle vertical scrolling, so I decided to share my solution with the hope that it would spare someone an hour or two .

+50
android horizontalscrollview swiperefreshlayout
Jun 02 '14 at 8:07
source share
3 answers

I solved it by extending SwipeRefreshLayout and overriding it onInterceptTouchEvent . Inside, I calculate that the distance X that the user visited is greater than the touch. If so, that means the user clicks horizontally, so I return false , which allows the child to view ( HorizontalScrollView in this case) to receive a touch event.

 public class CustomSwipeToRefresh extends SwipeRefreshLayout { private int mTouchSlop; private float mPrevX; public CustomSwipeToRefresh(Context context, AttributeSet attrs) { super(context, attrs); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPrevX = MotionEvent.obtain(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); } } 
+145
Jun 02 '14 at 8:07
source share

If you don’t remember the fact that you already rejected the ACTION_MOVE event, you will eventually take it later if the user returns to your original mPrevX.

Just add a boolean to remember it.

 public class CustomSwipeToRefresh extends SwipeRefreshLayout { private int mTouchSlop; private float mPrevX; // Indicate if we've already declined the move event private boolean mDeclined; public CustomSwipeToRefresh(Context context, AttributeSet attrs) { super(context, attrs); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPrevX = MotionEvent.obtain(event).getX(); mDeclined = false; // New action break; case MotionEvent.ACTION_MOVE: final float eventX = event.getX(); float xDiff = Math.abs(eventX - mPrevX); if (mDeclined || xDiff > mTouchSlop) { mDeclined = true; // Memorize return false; } } return super.onInterceptTouchEvent(event); } } 
+27
Jun 27 '14 at 13:34
source share

If you are using Tim Roes EnhancedListView

See issues . I was very useful for me because they add a function that detects when the swipe starts and when the swipe ends.

When starting a saber, I turn off SwipeRefreshLayout and, when we finish the swipe, I can use swipeRefreshLayout.

0
Aug 29 '14 at 8:31
source share



All Articles