onClick на ViewPager не срабатывает

Я установил прослушиватель кликов на ViewPager, но событие onClick никогда не вызывается. Я предполагаю, что обнаружение сенсорного события ViewPager мешает, но я не вижу, как это решить...

Кто-нибудь может помочь?

Спасибо

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

person jul    schedule 20.04.2012    source источник
comment
то, что вы хотите сделать с Click, может помочь найти другое решение.   -  person Herry    schedule 20.04.2012
comment
Я хочу что-то вроде ListView onItemClickListener()   -  person jul    schedule 20.04.2012
comment
означает, что вам нужно знать, какой элемент щелкает в ViewPager. Это означает, что позиция страницы щелкает, я прав?   -  person Herry    schedule 20.04.2012
comment
Фактический список не конфликтует с просмотрщиками. Настройка onClickListeners под ViewPager тоже должна работать нормально.   -  person bhekman    schedule 03.07.2012


Ответы (8)


Действительно, вьюпейджер мешает. Но вы можете переопределить методы вьюпейджера, чтобы заставить его делать то, что вы хотите. Вам потребуется переопределить ViewGroup.onInterceptTouchEvent(MotionEvent ev) метод.

Вы всегда можете просто вернуть false, чтобы события касания не проходили. Я бы также рекомендовал вызывать super.onInterceptTouchEvent(ev), чтобы свайпы продолжали работать.

Он проходит в MotionEvent, поэтому при желании вы можете проверить наличие кликов.

Надеюсь, это поможет. По крайней мере, это должно помочь вам начать. Отправьте сообщение с вопросами или дополнительными проблемами.

РЕДАКТИРОВАТЬ:

Также обратите внимание, что ViewPager не использует клики. Поэтому вы можете легко установить onclicklistener для любого или всех дочерних элементов окна просмотра, если хотите перехватывать клики и потенциально сэкономить себе много работы.

person bhekman    schedule 03.07.2012
comment
входит ли это в мой подкласс PagerAdapter? Как/где будет написано это переопределение? - person CQM; 28.01.2013
comment
@CQM также вы можете реализовать его как ViewPager.setOnTouchListener() - person Viacheslav; 04.09.2013
comment
Для меня в OnTouchListener ViewPager он не пересылает событие ACTION_DOWN, просто начинается с ACTION_MOVE, за которым следует ACTION_UP при перетаскивании, и ничего не отправляет, когда вы просто щелкаете по нему, поэтому кажется, что переопределение onInterceptTouchEvent может быть единственное решение. - person reactive-core; 24.10.2015

Я решил аналогичную проблему с помощью GestureDetector.

Отправка MotionEvent в GestureDetector

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

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

Если вы используете библиотеку совместимости, вы можете изменить первую строку на:

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

Вы можете обработать свое событие в GestureListener:

        class TapGestureListener extends GestureDetector.SimpleOnGestureListener{

         @Override
         public boolean onSingleTapConfirmed(MotionEvent e) {
           // Your Code here
         }
        }
person Martin Christmann    schedule 26.07.2012
comment
Спасибо, это сработало для меня, так как я не мог расширить ViewPager. - person n0rm1e; 29.06.2013
comment
Это то, что ищет +1 для этого - person Manwal; 11.04.2014
comment
Рассмотрим onSingleTapUp вместо onSingleTapConfirmed, если вы хотите, чтобы событие запускалось при нажатии, например, setOnClickListener. В противном случае событие будет запущено через некоторое время, убедившись, что за ним не последует второе касание. - person minipif; 19.07.2014
comment
Большое спасибо! Отлично работает! - person Hoàng Toản; 16.04.2015

я так делала...

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;
    }
});
person Kalpesh    schedule 07.11.2012
comment
Я не понимаю, насколько это уродливое решение. - person Fingolfin; 26.01.2016

Я знаю, что это старая тема, но я думаю, что это гораздо более простое решение.

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!");
        }
    }
);
person MarekZeman91    schedule 08.07.2014
comment
Nexus 5 отправит ACTION_MOVE при нажатии, если ваш палец немного сдвинется. - person Cremons; 18.07.2014
comment
Не работает на моем Nexus 5 (Android 6.0), я просто получаю ACTION_DOWN, за которым следует ACTION_UP. - person Jeroen Mols; 09.12.2015

Хотя это не прямой ответ на то, как запустить onClick, он вполне может быть полезным ответом на связанную проблему — захват событий кликов в ViewPager.

Просто добавьте атрибут onClick в XML-файл макета для элемента пейджера и добавьте метод в свою активность.

Образец кода:

Адаптер пейджера:

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);
        // ... 

макет 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>

Основная активность:

  public class MainActivity extends Activity {
  /* 
   ...
  */
    public void handleAction(View view) {
      // do your stuff
    }
  }
person J.G.Sebring    schedule 20.10.2014
comment
Не удалось найти метод handleAction(View) в родительском или предковом контексте для атрибута android:onClick, определенного в классе представления Получение этой ошибки @Tapirboy - person tahsinRupam; 21.07.2019
comment
Метод @tahsinRupam handleAction(View) — это ваш собственный метод, вам нужно его реализовать. - person J.G.Sebring; 15.08.2019

Вы можете установить фокусируемость ViewPager так, чтобы его дочерние элементы не могли получать сенсорные события, а вместо этого принимали их.

person ScouseChris    schedule 20.04.2012
comment
нет, не работает, если просмотр пейджера встроен в список или прокрутку - person Mightian; 08.06.2015

Убедитесь, что одно из непреднамеренных представлений на странице не потребляет событие клика. У меня была проблема, когда android:clickable был истинным в представлении изображения, и я не мог получить событие click от его родителя. После удаления этого android:clickable из представления изображения события щелчка теперь отправляются его родительскому элементу (BannerView). См. пример кода

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);               
            }
     });

}

}

person tmin    schedule 05.12.2013

Правильный способ сделать это — внедрить ViewPager.OnPageChangeListener в свою активность. Вот пример:

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) {
    }

}
person Lee Hounshell    schedule 07.03.2017