ViewPager上的onClick事件没有被触发

60

我在ViewPager上设置了一个点击监听器,但是onClick事件从未被调用。我猜测ViewPager的触摸事件检测正在干扰,但我不知道如何解决...

有人能帮忙吗?

谢谢

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

1
你想通过点击做什么,这可能会帮助提供另一种解决方案。 - Herry
我想要类似ListView的onItemClickListener()的东西。 - jul
你想知道在ViewPager中点击了哪个项目,也就是点击了哪个页面位置,对吗? - Herry
实际的ListView不会与ViewPager冲突。在ViewPager下设置onClickListeners也应该可以正常工作。 - bhekman
8个回答

106

我通过使用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
         }
        }

1
谢谢,这对我很有用,因为我无法扩展ViewPager。 - n0rm1e
1
这就是正在寻找的东西,再加上1。 - Manwal
5
如果您希望在单击时触发事件,就像setOnClickListener一样,请考虑使用onSingleTapUp,而不是onSingleTapConfirmed。否则,事件将在一段时间后触发,以确保它不会被第二次点击跟随。 - minipif
2
非常感谢!运行完美! - Hoàng Toản

23

我不喜欢那样做...

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

我看不出这是一个“丑陋”的解决方案。 - Fingolfin

21

确实,ViewPager正在干扰。但你可以覆盖ViewPager的方法使其按照你想要的方式运行。你需要重写ViewGroup.onInterceptTouchEvent(MotionEvent ev)方法。

你只需要始终返回false以允许触摸事件穿过即可。我还建议调用super.onInterceptTouchEvent(ev)以保持滑动的正常工作。

它传递了一个MotionEvent,因此如果你愿意,你可以通过检查它来查找点击。

希望这能帮到你。它至少可以让你开始。如果有问题或进一步的问题,请回复。

编辑:

请注意,ViewPager不会消耗点击事件。因此,如果您想捕获点击并潜在地节省大量工作,您可以轻松地在ViewPager的任何一个或所有子项上设置onclicklistener。


这个代码应该放在我的 PagerAdapter 子类中吗?这个重写应该在哪里编写? - CQM
3
@CQM,你也可以将其实现为ViewPager.setOnTouchListener()。 - Viacheslav
对我来说,在ViewPager的OnTouchListener中,它不会转发ACTION_DOWN事件,只是从ACTION_MOVE开始,当你拖动时跟随ACTION_UP,而当你只是点击它时,它不会发送任何东西,因此似乎覆盖onInterceptTouchEvent可能是唯一的解决方案。 - reactive-core

5

我知道这个话题有些老了,但我认为这是更简单的解决方案。

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

3
如果您的手指只移动了一点点,Nexus 5 在点击时将发送 ACTION_MOVE。 - Cremons
1
我的 Nexus 5(Android 6.0)上无法工作,我只收到一个 ACTION_DOWN,然后是 ACTION_UP。 - Jeroen Mols

3

虽然这不是如何触发onClick的直接答案,但它很可能是解决相关问题(在ViewPager中捕获点击事件)的有用答案。

只需在您的布局XML文件中为页面项添加onClick属性,并在您的Activity中添加该方法即可。

示例代码:

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

布局 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
    }
  }

在Android视图类的onClick属性中定义的handleAction(View)方法找不到其父级或祖先上下文。@Tapirboy遇到了这个错误。 - tahsinRupam
@tahsinRupam 方法 handleAction(View) 是您自己的自定义方法,您需要实现它。 - J.G.Sebring

0

您可以设置 ViewPager 的焦点能力,使其子项无法接收触摸事件,而是由它自己处理。


不行,如果ViewPager嵌套在ListView或ScrollView中。 - Mightian

0

确保页面中的一个意外视图不会消耗点击事件。我曾经遇到过这样的问题,即在图像视图上android:clickable为true,但我无法从其父级获取点击事件。在从图像视图中删除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);               
            }
     });

}

}


-2
正确的做法是在您的Activity中实现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) {
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接