项目需求:想在界面上实现双指向左、向右、向上、向下滑屏时触发不同的事件进行响应。
项目中遇到的问题:
1、Activity中重写onTouchEvent事件触发冲突
1)当Activity中不包含ScrollView时,重写onTouchEvent事件,会被触发;
2)当Activity中包含ScrollView时,ScrollView会消费掉onTouch事件,把Activity的onTouchEvent事件拦截,此时在Activity中重写onTouchEvent事件,是不会被触发的。
解决办法:重写界面上需要触发双指的View,在自定义View中重写onTouchEvent事件。
2、MotionEvent事件多指触屏时机判断
在网上搜索都是如下知识点:event.getAction()有以下几个触发事件
- ACTION_DOWN:触控时,总是第一个被触发,之后就不会再触发
- ACTION_POINTER_DOWN:只要还有触控点在屏幕上,之后手指下去都是之触发这个事件
- ACTION_UP:触控点离开时,仅当最后一个触控点消失时才会触发
- ACTION_POINTER_UP:只要还有触控点在屏幕上,每当手指离开都会触发这个事件
- ACTION_MOVE:可以获取按下触控点的位置(getX和getY)
按上面的理解,ACTION_POINTER_DOWN应该是大于等于两个手指触屏时才会被触发,可本人亲测的是,即使一个手指触屏,也会触发ACTION_POINTER_DOWN事件,按这个来判断是否有双指触屏不靠谱,应该用event.getPointerCount()来判断是否有多手指触屏。
3、自定义View双指触屏事件拦截
主要通过重写onTouchEvent方法,在MotionEvent.ACTION_MOVE事件中判断当有双指触摸时,请求父控件不要拦截触屏事件getParent().requestDisallowInterceptTouchEvent(true);,交给子控件自己处理,然后在MotionEvent.ACTION_UP中把控制权交回getParent().requestDisallowInterceptTouchEvent(false);。
public class MyTextView extends TextView { private int oldX1 = 0, oldX2 = 0, oldY1 = 0, oldY2 = 0, newX1 = 0, newY1 = 0, newX2 = 0, newY2 = 0, mScrollPointerId1, mScrollPointerId2; private boolean hasTwoFinger = false; private Context context; public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; } @Override public boolean onTouchEvent(MotionEvent event) { final int actionIndex = event.getActionIndex();//获取当前事件的索引 switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mScrollPointerId1 = event.getPointerId(actionIndex); oldX1 = (int)event.getX(); oldY1 = (int)event.getY(); case MotionEvent.ACTION_POINTER_DOWN://即使只有一个手指触屏,也会触发此事件 mScrollPointerId2 = event.getPointerId(actionIndex); oldX2 = (int)event.getX();//event.getX(0)是当前屏幕追踪手指的X轴位置 oldY2 = (int)event.getY();//event.getY(0)是当前屏幕追踪手指的Y轴位置 break; case MotionEvent.ACTION_POINTER_UP://第二个手指抬起 if (event.getPointerId(actionIndex) == mScrollPointerId1) {//判断离开屏幕的手指是不是当前追踪的手指 newX1 = (int)event.getX(); newY1 = (int)event.getY(); } else { newX2 = (int)event.getX(); newY2 = (int)event.getY(); } break; case MotionEvent.ACTION_MOVE: //不想要父视图拦截触摸事件 if (event.getPointerCount() == 2) { getParent().requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_UP: if (event.getPointerId(actionIndex) == mScrollPointerId1) {//判断离开屏幕的手指是不是当前追踪的手指 newX1 = (int)event.getX(); newY1 = (int)event.getY(); } else { newX2 = (int)event.getX(); newY2 = (int)event.getY(); } int distanceX1 = newX1 - oldX1; int distanceY1 = newY1 - oldY1; int distanceX2 = newX2 - oldX2; int distanceY2 = newY2 - oldY2; //Y方向上的 if (Math.abs(distanceY1) > Math.abs(distanceX1) && Math.abs(distanceY2) > Math.abs(distanceX2)) { if (distanceY1 > 0 && distanceY2 > 0) {//向下滑动 showShortToast("向下滑动"); } else if (distanceY1 < 0 && distanceY2 < 0) {//向上滑动 showShortToast("向上滑动"); } } else if(Math.abs(distanceY1) < Math.abs(distanceX1) && Math.abs(distanceY2) < Math.abs(distanceX2)){//X轴方向 if (distanceX1 > 0 && distanceX2 > 0) {//向右滑动 showShortToast("向右滑动"); } else if (distanceX1 < 0 && distanceX2 < 0) {//向左滑动 showShortToast("向左滑动"); } } getParent().requestDisallowInterceptTouchEvent(false); break; default: break; } return true; } private void showShortToast(String text) { Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); } }