27

I have a viewpager which switches between tabs when swiping left/right.In my second tab, i have some custom views which have listeners for pinching and dragging but when i try to pinch or drag, the viewpager starts to swipe the page.

A solution comes to my mind is to disable swiping when touching those specific views and only swipe when touching outside those views.Is this possible?

Updated: @Asok kindly provided the solution. But then updated the code which wouldnt work in my case so i post the previous piece of code which worked for me:

public class CustomViewPager extends ViewPager {
private boolean swipeable = true;

public CustomViewPager(Context context) {
    super(context);
}

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

// Call this method in your motion events when you want to disable or enable
// It should work as desired.
public void setSwipeable(boolean swipeable) {
    this.swipeable = swipeable;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
    return (this.swipeable) ? super.onInterceptTouchEvent(arg0) : false;
}

Lets suppose i have a draggable view and i need to disable swipping when dragging start and re enable when dragging finished so in TouchEvent of my so called view:

    @Override
public boolean onTouchEvent(MotionEvent event) {
    switch(event.getAction()) {
    case MotionEvent.ACTION_DOWN:
//disable swiping when the button is touched
((ActivityOriginal) getActivity()).setSwipeable(false);
//the rest of the code...
        break;
    case MotionEvent.ACTION_MOVE:

        break;
    case MotionEvent.ACTION_UP:
//re enable swipping when the touch is stopped
//the rest of the code...
((ActivityOriginal) getActivity()).setSwipeable(true);
        break;
    }
    return true;
}
Mehdi Fanai
  • 4,021
  • 13
  • 50
  • 75

4 Answers4

35

This first thing that comes to mind for me is to have a custom ViewPager in which, when your touch listeners get notified of a specific event you could set the swipeable boolean in ViewPager to false and set it back to true whichever way best fits your application.

public class CustomViewPager extends ViewPager {
    private boolean swipeable = true;

    public CustomViewPager(Context context) {
        super(context);
    }

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

    // Call this method in your motion events when you want to disable or enable
    // It should work as desired.
    public void setSwipeable(boolean swipeable) {
        this.swipeable = swipeable;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        return (this.swipeable) ? super.onInterceptTouchEvent(arg0) : false; 
    }

}

Make sure to change your layout file to show:

<com.your.package.CustomViewPager .. />

Instead of:

<android.support.v4.view.ViewPager .. />

Edit 2

Here is my setup (Working with the above CustomViewPager):

CustomViewPager mViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Set up the action bar.
    final ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    // Create the adapter that will return a fragment for each of the three
    // primary sections of the app.
    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

    // Set up the CustomViewPager with the sections adapter.
    mViewPager = (CustomViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);
    mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            actionBar.setSelectedNavigationItem(position);
        }
    });

    // For each of the sections in the app, add a tab to the action bar.
    for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
        actionBar.addTab(actionBar.newTab()
                .setText(mSectionsPagerAdapter.getPageTitle(i))
                .setTabListener(this));
    }

}

public void swipeOn(View v) {
    mViewPager.setSwipeable(true);
}

public void swipeOff(View v) {
    mViewPager.setSwipeable(false);
}

The above shown onCreate is in my MainActivity class which extends FragmentActivity and implements ActionBar.TabListener

jnthnjns
  • 8,962
  • 4
  • 42
  • 65
  • @asok how can i access to the customviewpager instance(which is created in the activity) from different fragments? – Mehdi Fanai May 02 '13 at 17:59
  • @Asok unfortunately none of UI elements react to touch,even buttons and list views after just using the customviewpager instead of viewpager. – Mehdi Fanai May 02 '13 at 18:12
  • 4
    @afterburner Sorry about that, instead of `onInterceptTouchEvent` try `onTouchEvent`, I tested and it was working for me by disabling swipe and no other touch event. – jnthnjns May 02 '13 at 20:03
  • @androiddeveloper After I corrected myself it is working and able to be switched on and off. – jnthnjns May 02 '13 at 20:21
  • @afterburner Also as a side note, when disabling the swipe, as I show, it still allows for the user to press the tab to switch pages if you use tabs. This is something I use in my application, should work for your purpose. Let me know if you have any questions. – jnthnjns May 02 '13 at 20:51
  • 2
    @Asok onInterceptTouchEvent did the trick for me but onTouchEvent(when the sweap was set to false the tabs were still sweapable but the sweap was slow like 1mm in each sweap).so i used onInterceptTouchEvent .Thank you for helping out. Just hope i could give you a lot more points for solving this problem. – Mehdi Fanai May 03 '13 at 07:48
  • I am facing similar problem (like http://stackoverflow.com/q/8122460/2624806) where view getting shifting in x-direction even after disable it...any solution/suggestion here>? – CoDe Mar 02 '14 at 20:17
  • Nice one .Helped me a lot .+1 – IntelliJ Amiya Nov 09 '15 at 06:59
35

I am using requestDisallowInterceptTouchEvent(true) int the onTouchEvent listener of the view that also has drag events.

@Override
public boolean onTouchEvent(MotionEvent event) {

    ViewParent parent = getParent(); 
    // or get a reference to the ViewPager and cast it to ViewParent

    parent.requestDisallowInterceptTouchEvent(true);

    // let this view deal with the event or
    return super.onTouchEvent(event);
}
Tiago A.
  • 2,568
  • 1
  • 22
  • 27
0

I am using like this

public void setSwipeable(boolean swipeable)
{
    this.swipeable = swipeable;
}

@Override
public void scrollTo(int x, int y){
    if (swipeable){
        super.scrollTo(x, y);
    }
}
Ray
  • 468
  • 4
  • 17
0

If you know the positions on which you don't want to intercept touch events in the view pager you can do something like I did.

 @Override
 public boolean onInterceptTouchEvent(MotionEvent arg0) {
    if(arg0.getY()>getHeight()/2)return false;
    return super.onInterceptTouchEvent(arg0);
}
wings
  • 338
  • 4
  • 15