最近在做页面的右滑手势返回时发现,当Activity里面整体是一个listView时,listView的item中的控件设置了onClickListener后,那么水平向右滑动的时候,会触发item中的控件的单击事件。假设这个单击事件是打开一个dialog形式的操作选项列表,就会发现:这个操作选项会弹出,然后紧接着当前Activity退出,这种体验不是很好。新浪微博也存在此问题。
自己项目中的复现此问题:
新浪微博复现此问题(模拟器上面不好复现,真机上面容易些):
以上可以明显看到先进入视频播放,再退出了当前Activity。
解决办法:在activity中设置一个标志位:mMoveState,在activity的dispatchTouchEvent中设置其状态,区分单击和滑动
@Override public boolean dispatchTouchEvent(MotionEvent ev) { mGestureDetector.onTouchEvent(ev); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mMoveState = false; break; case MotionEvent.ACTION_MOVE: mMoveState = true; break; case MotionEvent.ACTION_UP: break; } return super.dispatchTouchEvent(ev); }
在onClickListener中判断,当mMoveState为false(完全没有滑动)时才执行被点击的业务逻辑,这样就避免了上述问题。
ViewHolder.get(convertView, R.id.post_detail_list_image).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!mMoveState) { //单击后的业务逻辑 } } });
缺点:触摸事件要完全没有 MotionEvent.ACTION_MOVE 状态,才能被识别为单击事件。但是有时候用户的一个单击操作,也有可能有MotionEvent.ACTION_MOVE 状态,此时不被当成单击。
简而言之,识别为单击事件的条件更苛刻了。
改进:短距离的ACTION_MOVE不设置mMoveState为true。
@Override public boolean dispatchTouchEvent(MotionEvent ev) { mGestureDetector.onTouchEvent(ev); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mMoveState = false; x1 = ev.getX(); y1 = ev.getY(); break; case MotionEvent.ACTION_MOVE: //手势识别 if (Math.sqrt(Math.abs(x1 - ev.getX()) * Math.abs(x1 - ev.getX()) + Math.abs(y1 - ev.getY()) * Math.abs(y1 - ev.getY())) > 50) { mMoveState = true; } break; } return super.dispatchTouchEvent(ev); }