两种方式处理ViewPager点击事件

我们知道,ViewPager 没有点击事件,许多时候,需要设置点击事件,比如轮询广告点击事件,这时候怎么处理呢?我总结了两种方式:

  • 对 ViewPager 的每个页面设置点击事件
  • 通过onTouch()方法处理

下面分别说明一下:

(一)对 ViewPager 的每个页面设置点击事件

比如这种广告轮询,如果想要点击进入,就要给详情页面传入一个id,详情页通过网址+id(比如www.xxxxx/id)访问数据。那么,首先要说明的是这个是ViewPager+Fragment做的,适配器用的是PagerAdapter(后来我也尝试了用FragmentStatePagerAdapter,下面会说明)。

两种方式处理ViewPager点击事件_第1张图片

代码如下:

 @Override
    public Object instantiateItem(final ViewGroup container, final int position) {
        View view = viewList.get(position);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    callBack.callBack(position);
                }
            });
        container.addView(view);
        return view;
    }

直接给填充Fragment的视图设置点击事件,我这里用了一个回调(这个模式不懂的话自己查一下,不是很难),直接在在回调处做事件处理:

@Override
    public void callBack(int position) {
        Intent intent = new Intent(getActivity(), TeaDetailsActivity.class);
        intent.putExtra("id", adList.get(position).getId());
        startActivity(intent);
    }

【注】
如果用的适配器是FragmentStatePagerAdapter,因为它没有instantiateItem()方法,则可以在Fragment的onCreateView()中设置点击事件。


(二)通过onTouch()方法处理

首先说明,我参考了关于ViewPager的点击事件的处理(感谢作者),这篇文章思路是,点下屏幕时,设置一个flag为0,移动时为-1,抬起手指时,如果 flag==-1 说明是滑动事件(用于切换 ViewPgaer),此时不触发单击事件(用户滑动界面而非点击进入详情);如果 flag==0,则说明是单击事件。

说真的,我试了,结果不行。可能和机型有关吧,我用的是Android7.0系统,我 debug 的时候,发现无论怎么点击,都会触发移动的动作:

 case MotionEvent.ACTION_MOVE:
               flag = -1 ;
               break ;

此时,我在 MotionEvent.ACTION_UP 里面写的代码都没有调用:

  if (flag == 0) {//debug的时候发现 flag == -1
  //代码操作
  }

于是我尝试在 MotionEvent.ACTION_DOWN 和 MotionEvent.ACTION_MOVE 的时候分别打印当前的坐标 x,y 值,我发现 x,y 的值都没有变化,就是说,即使手指在屏幕上没有滑动,也会触发 MotionEvent.ACTION_MOVE 事件

怎么办呢?我请教了我的基友(下面简称他为黄),黄先是查看ViewPager类中的源码,有一块是关于ViewPager点击事件的:

case MotionEvent.ACTION_MOVE:
                if (!mIsBeingDragged) {
                    final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
                    if (pointerIndex == -1) {
                        // A child has consumed some touch events and put us into an inconsistent state.
                        needsInvalidate = resetTouch();
                        break;
                    }
                    final float x = MotionEventCompat.getX(ev, pointerIndex);
                    final float xDiff = Math.abs(x - mLastMotionX);
                    final float y = MotionEventCompat.getY(ev, pointerIndex);
                    final float yDiff = Math.abs(y - mLastMotionY);
                    if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
                    if (xDiff > mTouchSlop && xDiff > yDiff) {
                        if (DEBUG) Log.v(TAG, "Starting drag!");
                        mIsBeingDragged = true;
                        requestParentDisallowInterceptTouchEvent(true);
                        mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
                                mInitialMotionX - mTouchSlop;
                        mLastMotionY = y;
                        setScrollState(SCROLL_STATE_DRAGGING);
                        setScrollingCacheEnabled(true);

                        // Disallow Parent Intercept, just in case
                        ViewParent parent = getParent();
                        if (parent != null) {
                            parent.requestDisallowInterceptTouchEvent(true);
                        }
                    }
                }

有一点长,其中有一个变量叫做 mTouchSlop ,对于它的处理很容易理解:

 if (xDiff > mTouchSlop && xDiff > yDiff) {
 //一些操作
 }

xDiff 和 yDiff 是 x 和 y 方向上的移动距离(取绝对值),左右滑动时,x 方向上的变化值大于 mTouchSlop ,而且 xDiff 应该大于 yDiff (上下滑动视为无效),黄跟我说,他猜这个 mTouchSlop 应该就是判断ViewPager是否切换页面的滑动临界值,左右滑动超过这个值,页面就会滑到上一个或者下一个界面(看你往哪个方向滑了)。

至此,黄说对我说,如果不想干扰 ViewPager 的滑动事件,又想给 ViewPager 设置点击事件,可以在 mTouchSlop 上面做一些操作。简单的讨论之后,我们就搞定了:

headVp.setOnTouchListener(new View.OnTouchListener() {
                int touchFlag = 0;
                float x = 0, y = 0;

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            touchFlag = 0;
                            x = event.getX();
                            y = event.getY();
                            break;
                        case MotionEvent.ACTION_MOVE:
                            float xDiff = Math.abs(event.getX() - x);
                            float yDiff = Math.abs(event.getY() - y);
                            if (xDiff < mTouchSlop && xDiff >= yDiff)
                                touchFlag = 0;
                            else
                                touchFlag = -1;
                            break;
                        case MotionEvent.ACTION_UP:
                            if (touchFlag == 0) {
                                int currentItem = headVp.getCurrentItem();
                                Intent it = new Intent();
                                it.setClass(getActivity(), NewsDetailsActivity.class);
                                it.putExtra("story_id", topStories.get(currentItem).getId());
                                startActivity(it);
                            }
                            break;
                    }
                    return false;
                }
            });

对了!黄还教了我如何取到 mTouchSlop 的值(也是源码当中的):

ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);

至此,问题就都解决了。最后附上项目代码:
茶百科
逼乎日报

你可能感兴趣的:(android开发)