onClick on ViewPager not triggered

AndroidAndroid Viewpager

Android Problem Overview


I set a click listener on a ViewPager, but the onClick event is never called. I guess the touch event detection of the ViewPager is interfering, but I can't see how to solve it...

Anybody could help?

Thanks

mViewPager.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        // never called
    }
}); 

Android Solutions


Solution 1 - Android

I solved a similar problem by using a GestureDetector

Sending the MotionEvent to the GestureDetector

tapGestureDetector = new GestureDetector(this, new TapGestureListener());
	
viewPager.setOnTouchListener(new OnTouchListener() {
		public boolean onTouch(View v, MotionEvent event) {
			tapGestureDetector.onTouchEvent(event);
			return false;
		}
});

It you are using the compatibility library, you can change the first line to:

tapGestureDetector = new GestureDetectorCompat(this, new TapGestureListener());

You can handle your Event in the GestureListener:

    	class TapGestureListener extends GestureDetector.SimpleOnGestureListener{
		
		 @Override
		 public boolean onSingleTapConfirmed(MotionEvent e) {
           // Your Code here
         }
	    }

Solution 2 - Android

I done like that...

mViewPager.setOnTouchListener(new View.OnTouchListener() {
	float oldX = 0, newX = 0, sens = 5;

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			oldX = event.getX();
			break;

		case MotionEvent.ACTION_UP:
			newX = event.getX();
			if (Math.abs(oldX - newX) < sens) {
				itemClicked(mViewPager.getCurrentItem());
				return true;
			}
			oldX = 0;
			newX = 0;
			break;
		}

		return false;
	}
});

Solution 3 - Android

Indeed the viewpager is interfering. But you can override the methods of the viewpager to make it do what you want. You'll need to override the ViewGroup.onInterceptTouchEvent(MotionEvent ev) method.

You could just always return false to allow the touch events to fall through. I would also recommend calling super.onInterceptTouchEvent(ev) to allow swipes to keep working.

It passes in a MotionEvent, so you could check for clicks with that if you wanted.

Hope that helps. It should at least get you started. Post back with questions or further problems.

EDIT:

Note also that the ViewPager doesn't consume clicks. Therefore you could easily set an onclicklistener on any or all of the children of the viewpager if you wanted to capture clicks and potentially save yourself a lot of work.

Solution 4 - Android

I know it's kinda old topic but I think this is much easier solution.

ViewPager viewPager = new ViewPager(this);
viewPager.setAdapter(yourPagerAdapter);

// somewhere where you setup your viewPager add this
viewPager.setOnTouchListener(
    new View.OnTouchListener() {
        private boolean moved;

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                moved = false;
            }
            if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
                moved = true;
            }
            if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
                if (!moved) {
                    view.performClick();
                }
            }

            return false;
        }
    }
);

// then you can simply use the standard onClickListener ...
viewPager.setOnClickListener(
    new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            Log.i(LOG, "Dayum!");
        }
    }
);

Solution 5 - Android

While this is not an direct answer to how get the onClick triggered, it might very well be an useful answer to the related problem - capturing click events in ViewPager.

Simply add the onClick attribute in your layout xml file for the pager item and add the method in your activity.

Sample code:

PagerAdapter:

class SamplePagerAdapter extends PagerAdapter {
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // Inflate a new layout from our resources
        View view = getActivity().getLayoutInflater().inflate(R.layout.pager_item,
                container, false);
        // Add the newly created View to the ViewPager
        container.addView(view);
        // ... 

layout pager_item.xml

<?xml version="1.0" encoding="utf-8"?>

  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    // usual attributes
  >

    <ImageButton 
      // usual attributes
      android:onClick="handleAction"
    />

 </LinearLayout>

MainActivity:

  public class MainActivity extends Activity {
  /* 
   ...
  */
    public void handleAction(View view) {
      // do your stuff
    }
  }

Solution 6 - Android

You can set the focusability of the ViewPager so that it's children can't receive touch events and it takes them instead.

Solution 7 - Android

Make sure that one of the unintended views inside the page is not consuming click event. I had an issue where android:clickable was true on the image view and I could not get click event from its parent. After removing that android:clickable from image view, the click events are sent to its parent (BannerView) now. See the example code

public ViewPagerAdapter extends PagerAdapter {
...

public Object instantiateItem (ViewGroup container, int position) {

	MyItem item = this.myItems.get(position);

	BannerView bannerView = new BannerView(container.getContext());
	ImageView imageView = (ImageView) bannerView.findViewById(R.id.header_image);

	this.setupClickListener(bannerView, position);

	 container.addView(bannerView);
	 return bannerView;
}

private void setupClickListener(final BannerView view, final int position) {
    
    view.setOnClickListener(new OnClickListener() {
        
            @Override
            public void onClick(View v) {
			
			   // Page is clicked!
               MyItem item = ViewPagerAdapter.this.myItems.get(position);
               ViewPagerAdapter.this.showNextActivity(view.getContext(), item);               
            }
     });
    
}

}

Solution 8 - Android

The proper way to do this is to implement ViewPager.OnPageChangeListener in your Activity. Here is an example:

public class MyActivity implements ViewPager.OnPageChangeListener
{

    private ViewPager mViewPager;
    private int mLastPagePosition = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        mViewPager = (ViewPager) findViewById(R.id.viewpager);
        mViewPager.addOnPageChangeListener(this);

        ...
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (mLastPagePosition != position) {
            // the selected page is changed
            mLastPagePosition = position;
        }
    }

    @Override
    public void onPageSelected(int position) {
        if (mLastPagePosition != position) {
            // the selected page is changed
            mLastPagePosition = position;
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjulView Question on Stackoverflow
Solution 1 - AndroidMartin ChristmannView Answer on Stackoverflow
Solution 2 - AndroidKalpeshView Answer on Stackoverflow
Solution 3 - AndroidbhekmanView Answer on Stackoverflow
Solution 4 - AndroidMarekZeman91View Answer on Stackoverflow
Solution 5 - AndroidJ.G.SebringView Answer on Stackoverflow
Solution 6 - AndroidScouseChrisView Answer on Stackoverflow
Solution 7 - AndroidtminView Answer on Stackoverflow
Solution 8 - AndroidLee HounshellView Answer on Stackoverflow