Android Listview inside ViewPager, No horizontal swipe - android

I have an activity holding a viewpager. One of the fragments in the viewpager includes a listview that covers almost the entire screen but only passively has to display items (no click on items required).
I've tried several options found on SO to disable clicks on the listview and/or it's adapter or building listener that do not consume the listview/adapter's clicks, etc. but none solved my issue:
When the listview is full of items I have to swipe at the very outer border of the display to move to another fragment of the viewpager. On the other fragments for example I dont have listviews but other views like maps and can swipe between the fragments when doing the swipe gesture directly on the middle of the display.
For a consistent user experience I also want this behaviour on the fragment holding the passive listview.
Thank you.

Create a custom ViewPager by extending it and implement dispatchTouchEvent.
We start tracking the touch ( with the pixel positions on sceen ) in ACTION_DOWN. When we see that it's a horizontal swipe, we do not call super.dispatchTouchEvent( event ) - which would do the default onTouch routing and make certain child views consume the horizontal swipe too - but call onTouchEvent( event ) instead in ACTION_MOVE and also in ACTION_UP.
public class MyViewPager extends ViewPager {
private float mLastX;
private float mLastY;
private final int mTouchSlop = ViewConfiguration.get( getContext() ).getScaledTouchSlop();
private float mStartX;
public MyViewPager( Context context ) {
super( context );
}
public MyViewPager( Context context, AttributeSet attrs ) {
super( context, attrs );
}
#Override
public boolean dispatchTouchEvent( MotionEvent event ) {
switch( event.getAction() ) {
case MotionEvent.ACTION_DOWN:
mLastX = event.getX();
mLastY = event.getY();
mStartX = event.getX();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
onTouchEvent( event );
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
float xDelta = x - mLastX;
float xDeltaAbs = Math.abs( xDelta );
float yDeltaAbs = Math.abs( y - mLastY );
float xDeltaTotal = x - mStartX;
if( Math.abs( xDeltaTotal ) > mTouchSlop )
if( xDeltaAbs > yDeltaAbs )
return onTouchEvent( event );
}
return super.dispatchTouchEvent( event );
}
}

public boolean onTouch(View v, MotionEvent e) {
if(e.getAction() == MotionEvent.ACTION_DOWN){
listItem.getParent().requestDisallowInterceptTouchEvent(true);
}
}

Related

OnTouch event on Screen

I have xml in which I have 2 relative layouts, the first one is map(using map fragments) and the second one is ViewPager layout. I added button to map to hide map when clicked, now I want a method to get back the map layout by sweep down the screen.
I tried setting onTouchListener to relative layout but it is not working, also tried implementing OnTouchListener
public class MainActivity extends FragmentActivity implements OnTouchListener
it is not working! how to achieve this?
#Override
public boolean onTouch(View v, MotionEvent event) {
x= event.getX();
y=event.getY();
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
sX = event.getX();
sY = event.getY();
break;
case MotionEvent.ACTION_UP:
fX = event.getX();
fY = event.getY();
if(fX-sX == 0 || fX-sX > 0 || fX-sX <0)
if(fY-sY < 0)
{
if(mapview.getVisibility()==View.GONE)
{
mapview.setVisibility(View.VISIBLE);
}
}
break;
}
return true;
}
Post your code, btw in simple way, ACTION_DOWN is when you touch the screen, ACTION_UP is when you finger release the screen. Look here

Correctly detecting a swipe on a GridView placed inside a ViewPager in Android

I have a ViewPager which uses GridViews for pages. I would like the ViewPager to switch pages when I swipe across the screen.
The problem is that swipes are not detected when they are made across the GridView. Outside of the GridView, the swipes work correctly; it seems that the GridView is trapping all touch events without passing it to ViewPager first.
While fiddling with the source code, I did this to a custom class extended from GridView:
#Override
public boolean onTouchEvent(MotionEvent event) {
return pager.onInterceptTouchEvent(event);
}
-- where pager refers to the ViewPager class. With this, ViewPager will correctly detect swipes and move pages accordingly, but it doesn't allow GridView to accept any events, so I can't click on the items.
What I would like to be able to do is correctly detect swipes in ViewPager and item clicks on GridView.
I had trouble with colig's implementation, but I was able to get it to work by subclassing ViewPager and overriding the onInterceptTouchEvent() method. I only checked for swipes in the X direction to allow for vertical scrolling if necessary.
private static final int minSwipeDistance = 30;
private float mTouchX;
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean response = super.onInterceptTouchEvent(event);
float x = event.getX();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mTouchX = x;
break;
case MotionEvent.ACTION_MOVE:
float dX = Math.abs(x - mTouchX);
if (dX > minSwipeDistance)
return true;
break;
}
return response;
}
Alix is on the right track. I managed to come up with this simple-looking fix. I'm not entirely sure of how it works, but it does! And for future reference, it works for other kinds of views too -- TableLayout, for example -- not just GridView.
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
x = event.getX();
y = event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
downX = x;
downY = y;
return super.onInterceptTouchEvent(event);
}
case MotionEvent.ACTION_MOVE: {
deltaX = Math.abs(downX - x);
deltaY = Math.abs(downY - y);
return super.onTouchEvent(event);
}
case MotionEvent.ACTION_UP: {
if (deltaX > 4 && deltaY > 4) {
super.onTouchEvent(event);
}
}
}
return super.onInterceptTouchEvent(event);
}
You can override onInterceptTouchEvent for dispatch evenement where you want

How to enable tap listener in view pager in Android?

I am using view pager to swipe between the views in Android.
Now I need to capture tap event for each of the views. when I override the touch listener to capture the tap event, the swipe action doesn't happen and the screen remains in the first page itself. How do I add touch listener to view pager?
Code:
viewPager.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event)
{
mDetector.onTouchEvent(event);
return true;
}});
For the above code I am able to capture tap event, but the swipe action becomes Impossible.
Here i leave you a snippet from my code to detect a "click" on the OnTouchListener, i hope it helps
mImagePager.setOnTouchListener(new OnTouchListener() {
private float pointX;
private float pointY;
private int tolerance = 50;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_MOVE:
return false; //This is important, if you return TRUE the action of swipe will not take place.
case MotionEvent.ACTION_DOWN:
pointX = event.getX();
pointY = event.getY();
break;
case MotionEvent.ACTION_UP:
boolean sameX = pointX + tolerance > event.getX() && pointX - tolerance < event.getX();
boolean sameY = pointY + tolerance > event.getY() && pointY - tolerance < event.getY();
if(sameX && sameY){
//The user "clicked" certain point in the screen or just returned to the same position an raised the finger
}
}
return false;
}
});
We can use Gestures (Link1, Link2):
public boolean onTouchEvent (MotionEvent ev)
Hope this helps!
Nancy, you don't need to manually override the Page swipes or the touch events. Just add the pages to the ViewPager and the ViewPager will automatically take care of swiping.
You do, however, have to attach touch listeners to the object in each page. So if Page 1 has a Linear Layout with many buttons and you need to find out when those buttons are clicked, you need to attach OnClickListeners for each of those buttons.
Do let me know your use case so we can better understand, why you need to find out when a page has been clicked!
Just to add to Jorge's great answer, you may just use distance instead of sameX and sameY, which is a bit more elegant. Sample:
// Ignore events that are swipes rather then touches
float distX = event.getX() - pointX;
float distY = event.getY() - pointX;
double dist = Math.sqrt(distX * distX + distY * distY);
if (dist > tolerance) {
return false;
}
Put the click event on the item view of the viewpager inside the viewPagerAdapter in the method instantiateItem like -
#Override
public Object instantiateItem(ViewGroup container, final int position) {
// Declare Variables
ImageView jive_image;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.list_item_viewpager, container,
false);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onBackPressed();
}
});
// Add viewpager_item.xml to ViewPager
((ViewPager) container).addView(itemView);
return itemView;
}

Android Gallery Flipping issue

I have a Gallery of views that contain a TextView Label and then a listview below that. It works excellent except that in order to get it to flip from element to element, the user has to touch either above the listview (near the label) and fling or in between gallery objects. Sometimes below the listview works too.But I really want to be able to fling while touching the listview too because it takes up a majority of the screen. How can this be done? What code do you need to see?
I had a similar problem and solved this by overriding the Gallery and implementing the onInterceptTouchEvent to ensure that move events are intercepted by the Gallery, and all other events are handled normally.
Returning true in the onInterceptTouchEvent causes all following touch events in this touch sequence to be sent to this view, false leaves the event for it's children.
TouchSlop is needed as when doing a click there is sometimes a small amount of movement.
Would love to claim this as my own idea, but got the basics of the code from the default Android Launcher code.
public class MyGallery extends Gallery{
private MotionEvent downEvent;
private int touchSlop;
private float lastMotionY;
private float lastMotionX;
public MyGallery(Context context) {
super(context);
initTouchSlop();
}
private void initTouchSlop() {
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
touchSlop = configuration.getScaledTouchSlop();
}
#Override public boolean onInterceptTouchEvent(MotionEvent ev) {
final float x = ev.getX();
final float y = ev.getY();
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
final int xDiff = (int) Math.abs(x - lastMotionX);
final int yDiff = (int) Math.abs(y - lastMotionY);
// have we moved enough to consider this a scroll
if (xDiff > touchSlop || yDiff > touchSlop) {
// this is the event we want, but we need to resend the Down event as this could have been consumed by a child
Log.d(TAG, "Move event detected: Start intercepting touch events");
if (downEvent != null) this.onTouchEvent(downEvent);
downEvent = null;
return true;
}
return false;
}
case MotionEvent.ACTION_DOWN: {
// need to save the on down event incase this is going to be a scroll
downEvent = MotionEvent.obtain(ev);
lastMotionX = x;
lastMotionY = y;
return false;
}
default: {
// if this is not a down or scroll event then it is not for us
downEvent = null;
return false;
}
}
}
You would want to set the onTouchListener() on the listview, or maybe the entire Linear/Relative layout.
getListView().setOnTouchListener(yourlistener) OR set it on the entire layout. If you post a little code, I could help you further. XML and how you are using in with the Java class would be most helpful.

HorizontalScrollView within ScrollView Touch Handling

I have a ScrollView that surrounds my entire layout so that the entire screen is scrollable. The first element I have in this ScrollView is a HorizontalScrollView block that has features that can be scrolled through horizontally. I've added an ontouchlistener to the horizontalscrollview to handle touch events and force the view to "snap" to the closest image on the ACTION_UP event.
So the effect I'm going for is like the stock android homescreen where you can scroll from one to the other and it snaps to one screen when you lift your finger.
This all works great except for one problem: I need to swipe left to right almost perfectly horizontally for an ACTION_UP to ever register. If I swipe vertically in the very least (which I think many people tend to do on their phones when swiping side to side), I will receive an ACTION_CANCEL instead of an ACTION_UP. My theory is that this is because the horizontalscrollview is within a scrollview, and the scrollview is hijacking the vertical touch to allow for vertical scrolling.
How can I disable the touch events for the scrollview from just within my horizontal scrollview, but still allow for normal vertical scrolling elsewhere in the scrollview?
Here's a sample of my code:
public class HomeFeatureLayout extends HorizontalScrollView {
private ArrayList<ListItem> items = null;
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;
private static final int SWIPE_MIN_DISTANCE = 5;
private static final int SWIPE_THRESHOLD_VELOCITY = 300;
private int activeFeature = 0;
public HomeFeatureLayout(Context context, ArrayList<ListItem> items){
super(context);
setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
setFadingEdgeLength(0);
this.setHorizontalScrollBarEnabled(false);
this.setVerticalScrollBarEnabled(false);
LinearLayout internalWrapper = new LinearLayout(context);
internalWrapper.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
internalWrapper.setOrientation(LinearLayout.HORIZONTAL);
addView(internalWrapper);
this.items = items;
for(int i = 0; i< items.size();i++){
LinearLayout featureLayout = (LinearLayout) View.inflate(this.getContext(),R.layout.homefeature,null);
TextView header = (TextView) featureLayout.findViewById(R.id.featureheader);
ImageView image = (ImageView) featureLayout.findViewById(R.id.featureimage);
TextView title = (TextView) featureLayout.findViewById(R.id.featuretitle);
title.setTag(items.get(i).GetLinkURL());
TextView date = (TextView) featureLayout.findViewById(R.id.featuredate);
header.setText("FEATURED");
Image cachedImage = new Image(this.getContext(), items.get(i).GetImageURL());
image.setImageDrawable(cachedImage.getImage());
title.setText(items.get(i).GetTitle());
date.setText(items.get(i).GetDate());
internalWrapper.addView(featureLayout);
}
gestureDetector = new GestureDetector(new MyGestureDetector());
setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL ){
int scrollX = getScrollX();
int featureWidth = getMeasuredWidth();
activeFeature = ((scrollX + (featureWidth/2))/featureWidth);
int scrollTo = activeFeature*featureWidth;
smoothScrollTo(scrollTo, 0);
return true;
}
else{
return false;
}
}
});
}
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
//right to left
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
activeFeature = (activeFeature < (items.size() - 1))? activeFeature + 1:items.size() -1;
smoothScrollTo(activeFeature*getMeasuredWidth(), 0);
return true;
}
//left to right
else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
activeFeature = (activeFeature > 0)? activeFeature - 1:0;
smoothScrollTo(activeFeature*getMeasuredWidth(), 0);
return true;
}
} catch (Exception e) {
// nothing
}
return false;
}
}
}
Update: I figured this out. On my ScrollView, I needed to override the onInterceptTouchEvent method to only intercept the touch event if the Y motion is > the X motion. It seems like the default behavior of a ScrollView is to intercept the touch event whenever there is ANY Y motion. So with the fix, the ScrollView will only intercept the event if the user is deliberately scrolling in the Y direction and in that case pass off the ACTION_CANCEL to the children.
Here is the code for my Scroll View class that contains the HorizontalScrollView:
public class CustomScrollView extends ScrollView {
private GestureDetector mGestureDetector;
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
}
// Return false if we're scrolling in the x direction
class YScrollDetector extends SimpleOnGestureListener {
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceY) > Math.abs(distanceX);
}
}
}
Thank you Joel for giving me a clue on how to resolve this problem.
I have simplified the code(without need for a GestureDetector) to achieve the same effect:
public class VerticalScrollView extends ScrollView {
private float xDistance, yDistance, lastX, lastY;
public VerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
xDistance = yDistance = 0f;
lastX = ev.getX();
lastY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
xDistance += Math.abs(curX - lastX);
yDistance += Math.abs(curY - lastY);
lastX = curX;
lastY = curY;
if(xDistance > yDistance)
return false;
}
return super.onInterceptTouchEvent(ev);
}
}
I think I found a simpler solution, only this uses a subclass of ViewPager instead of (its parent) ScrollView.
UPDATE 2013-07-16: I added an override for onTouchEvent as well. It could possibly help with the issues mentioned in the comments, although YMMV.
public class UninterceptableViewPager extends ViewPager {
public UninterceptableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean ret = super.onInterceptTouchEvent(ev);
if (ret)
getParent().requestDisallowInterceptTouchEvent(true);
return ret;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
boolean ret = super.onTouchEvent(ev);
if (ret)
getParent().requestDisallowInterceptTouchEvent(true);
return ret;
}
}
This is similar to the technique used in android.widget.Gallery's onScroll().
It is further explained by the Google I/O 2013 presentation Writing Custom Views for Android.
Update 2013-12-10: A similar approach is also described in a post from Kirill Grouchnikov about the (then) Android Market app.
I've found out that somethimes one ScrollView regains focus and the other loses focus. You can prevent that, by only granting one of the scrollView focus:
scrollView1= (ScrollView) findViewById(R.id.scrollscroll);
scrollView1.setAdapter(adapter);
scrollView1.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
scrollView1.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
It wasn't working well for me. I changed it and now it works smoothly. If anyone interested.
public class ScrollViewForNesting extends ScrollView {
private final int DIRECTION_VERTICAL = 0;
private final int DIRECTION_HORIZONTAL = 1;
private final int DIRECTION_NO_VALUE = -1;
private final int mTouchSlop;
private int mGestureDirection;
private float mDistanceX;
private float mDistanceY;
private float mLastX;
private float mLastY;
public ScrollViewForNesting(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
}
public ScrollViewForNesting(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ScrollViewForNesting(Context context) {
this(context,null);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDistanceY = mDistanceX = 0f;
mLastX = ev.getX();
mLastY = ev.getY();
mGestureDirection = DIRECTION_NO_VALUE;
break;
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
mDistanceX += Math.abs(curX - mLastX);
mDistanceY += Math.abs(curY - mLastY);
mLastX = curX;
mLastY = curY;
break;
}
return super.onInterceptTouchEvent(ev) && shouldIntercept();
}
private boolean shouldIntercept(){
if((mDistanceY > mTouchSlop || mDistanceX > mTouchSlop) && mGestureDirection == DIRECTION_NO_VALUE){
if(Math.abs(mDistanceY) > Math.abs(mDistanceX)){
mGestureDirection = DIRECTION_VERTICAL;
}
else{
mGestureDirection = DIRECTION_HORIZONTAL;
}
}
if(mGestureDirection == DIRECTION_VERTICAL){
return true;
}
else{
return false;
}
}
}
Thanks to Neevek his answer worked for me but it doesn't lock the vertical scrolling when user has started scrolling the horizontal view(ViewPager) in horizontal direction and then without lifting the finger scroll vertically it starts to scroll the underlying container view(ScrollView). I fixed it by making a slight change in Neevak's code:
private float xDistance, yDistance, lastX, lastY;
int lastEvent=-1;
boolean isLastEventIntercepted=false;
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
xDistance = yDistance = 0f;
lastX = ev.getX();
lastY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
xDistance += Math.abs(curX - lastX);
yDistance += Math.abs(curY - lastY);
lastX = curX;
lastY = curY;
if(isLastEventIntercepted && lastEvent== MotionEvent.ACTION_MOVE){
return false;
}
if(xDistance > yDistance )
{
isLastEventIntercepted=true;
lastEvent = MotionEvent.ACTION_MOVE;
return false;
}
}
lastEvent=ev.getAction();
isLastEventIntercepted=false;
return super.onInterceptTouchEvent(ev);
}
This finally became a part of support v4 library, NestedScrollView. So, no longer local hacks is needed for most of cases I'd guess.
Neevek's solution works better than Joel's on devices running 3.2 and above. There is a bug in Android that will cause java.lang.IllegalArgumentException: pointerIndex out of range if a gesture detector is used inside a scollview. To duplicate the issue, implement a custom scollview as Joel suggested and put a view pager inside. If you drag (don't lift you figure) to one direction (left/right) and then to the opposite, you will see the crash. Also in Joel's solution, if you drag the view pager by moving your finger diagonally, once your finger leave the view pager's content view area, the pager will spring back to its previous position. All these issues are more to do with Android's internal design or lack of it than Joel's implementation, which itself is a piece of smart and concise code.
http://code.google.com/p/android/issues/detail?id=18990
Date : 2021 - May 12
Looks jibberish..but trust me its worth the time if you wanna scroll any view horizontally in a vertical scrollview butter smooth!!
Works in jetpack compose as well by by making a custom view and extending the view that you wanna scroll horizontally in; inside a vertical scroll view and using that custom view inside AndroidView composable (Right now, "Jetpack Compose is in 1.0.0-beta06"
This is the most optimal solution if you wanna scroll horizontally freely and vertically freely without the vertical scrollbar intercepting ur touch when u are scrolling horizontally and only allowing the vertical scrollbar to intercept the touch when u are scrolling vertically through the horizontal scrolling view :
private class HorizontallyScrollingView #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : ViewThatYouWannaScrollHorizontally(context, attrs){
override fun onTouchEvent(event: MotionEvent?): Boolean {
// When the user's finger touches the webview and starts moving
if(event?.action == MotionEvent.ACTION_MOVE){
// get the velocity tracker object
val mVelocityTracker = VelocityTracker.obtain();
// connect the velocity tracker object with the event that we are emitting while we are touching the webview
mVelocityTracker.addMovement(event)
// compute the velocity in terms of pixels per 1000 millisecond(i.e 1 second)
mVelocityTracker.computeCurrentVelocity(1000);
// compute the Absolute Velocity in X axis
val xVelocityABS = abs(mVelocityTracker.getXVelocity(event?.getPointerId((event?.actionIndex))));
// compute the Absolute Velocity in Y axis
val yVelocityABS = abs(mVelocityTracker.getYVelocity(event?.getPointerId((event?.actionIndex))));
// If the velocity of x axis is greater than y axis then we'll consider that it's a horizontal scroll and tell the parent layout
// "Hey parent bro! im scrolling horizontally, this has nothing to do with ur scrollview so stop capturing my event and stay the f*** where u are "
if(xVelocityABS > yVelocityABS){
// So, we'll disallow the parent to listen to any touch events until i have moved my fingers off the screen
parent.requestDisallowInterceptTouchEvent(true)
}
} else if (event?.action == MotionEvent.ACTION_CANCEL || event?.action == MotionEvent.ACTION_UP){
// If the touch event has been cancelled or the finger is off the screen then reset it (i.e let the parent capture the touch events on webview as well)
parent.requestDisallowInterceptTouchEvent(false)
}
return super.onTouchEvent(event)
}
}
Here, ViewThatYouWannaScrollHorizontally is the view that you want to scroll horizontally in and when u are scrolling horizontally, you dont want the vertical scrollbar to capture the touch and think that "oh! the user is scrolling vertically so parent.requestDisallowInterceptTouchEvent(true) will basically say the vertical scroll bar "hey you! dont capture any touch coz the user is scrolling horizontally"
And after the user is done scrolling horizontally and tries to scroll vertically through the horizontal scrollbar which is placed inside a vertical scrollbar then it will see that the touch velocity in Y axis is greater than X axis, which shows user is not scrolling horizontally and the horizontal scrolling stuff will say "Hey you! parent, you hear me?..the user is scrolling vertically through me, now u can intercept the touch and show the stuffs present below me in the vertical scroll"

Categories

Resources