onTouch方法监听了用户的按下点击等事件,自然包括了onclick的单机事件
若一个view同时设置了这两个监听就会出现一些事件冲突。
我的项目中有一个zoomIMageView,随手势滑动的放大缩小的imageview控件,之前直接网上下载的。现在我把zoomImageView放在了viewPager中,设置单机事件后,onclick就不响应了,查看zoomImageView后就发现已经有ontouch响应了事件,所以必须对源码进行一些修改才能符合我的需求。
先看zoomImagView的onTouch方法:
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mGestureDetector.onTouchEvent(event))
return true;
mScaleGestureDetector.onTouchEvent(event);
float x = 0, y = 0;
// 拿到触摸点的个数
final int pointerCount = event.getPointerCount();
// 得到多个触摸点的x与y均值
for (int i = 0; i < pointerCount; i++) {
x += event.getX(i);
y += event.getY(i);
}
x = x / pointerCount;
y = y / pointerCount;
/**
* 每当触摸点发生变化时,重置mLasX , mLastY
*/
if (pointerCount != lastPointerCount) {
isCanDrag = false;
mLastX = x;
mLastY = y;
}
lastPointerCount = pointerCount;
RectF rectF = getMatrixRectF();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_MOVE:
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
// Log.e(TAG, "ACTION_MOVE");
float dx = x - mLastX;
float dy = y - mLastY;
if (!isCanDrag) {
isCanDrag = isCanDrag(dx, dy);
}
if (isCanDrag) {//是否可以推动
if (getDrawable() != null) {
if (getMatrixRectF().left == 0 && dx > 0) {
getParent().requestDisallowInterceptTouchEvent(false);
}
if (getMatrixRectF().right == getWidth() && dx < 0) {
getParent().requestDisallowInterceptTouchEvent(false);
}
isCheckLeftAndRight = isCheckTopAndBottom = true;
// 如果宽度小于屏幕宽度,则禁止左右移动
if (rectF.width() < getWidth()) {
dx = 0;
isCheckLeftAndRight = false;
}
// 如果高度小雨屏幕高度,则禁止上下移动
if (rectF.height() < getHeight()) {
dy = 0;
isCheckTopAndBottom = false;
}
mScaleMatrix.postTranslate(dx, dy);
checkMatrixBounds();
setImageMatrix(mScaleMatrix);
}
}
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// Log.e(TAG, "ACTION_UP");
lastPointerCount = 0;
break;
}
return true;
}
先测试return参数的作用是什么。这里不详解,直接写结果了。
1、return true消费了此次的触摸事件,其他事件将不再执行
2、return false 执行了ontouch方法,onclick事件也执行了,说明ontouch方法执行在onclick之前,这一点和onlongclick与onclick的关系是类似的
解决方案:在适当的时候让ontouch返回false
直接贴代码:
@Override
public boolean onTouch(View v, MotionEvent event) {
int flag = 0;
if (mGestureDetector.onTouchEvent(event))
return true;
mScaleGestureDetector.onTouchEvent(event);
float x = 0, y = 0;
// 拿到触摸点的个数
final int pointerCount = event.getPointerCount();
// 得到多个触摸点的x与y均值
for (int i = 0; i < pointerCount; i++) {
x += event.getX(i);
y += event.getY(i);
}
x = x / pointerCount;
y = y / pointerCount;
/**
* 每当触摸点发生变化时,重置mLasX , mLastY
*/
if (pointerCount != lastPointerCount) {
isCanDrag = false;
mLastX = x;
mLastY = y;
}
lastPointerCount = pointerCount;
RectF rectF = getMatrixRectF();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
flag = 0;
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_MOVE:
flag = 1;
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
// Log.e(TAG, "ACTION_MOVE");
float dx = x - mLastX;
float dy = y - mLastY;
if (!isCanDrag) {
isCanDrag = isCanDrag(dx, dy);
}
if (isCanDrag) {//是否可以推动
if (getDrawable() != null) {
if (getMatrixRectF().left == 0 && dx > 0) {
getParent().requestDisallowInterceptTouchEvent(false);
}
if (getMatrixRectF().right == getWidth() && dx < 0) {
getParent().requestDisallowInterceptTouchEvent(false);
}
isCheckLeftAndRight = isCheckTopAndBottom = true;
// 如果宽度小于屏幕宽度,则禁止左右移动
if (rectF.width() < getWidth()) {
dx = 0;
isCheckLeftAndRight = false;
}
// 如果高度小雨屏幕高度,则禁止上下移动
if (rectF.height() < getHeight()) {
dy = 0;
isCheckTopAndBottom = false;
}
mScaleMatrix.postTranslate(dx, dy);
checkMatrixBounds();
setImageMatrix(mScaleMatrix);
}
}
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// Log.e(TAG, "ACTION_UP");
lastPointerCount = 0;
break;
}
if (flag == 0) {
return false;
}
return true;
}
加了一个flag 判断是否是点击事件,如果是移动事件就返回true,不执行onclick方法,刚好也不会冲突。
使用时发现一些bug,zoomIMageView双手点击时也响应了单击事件,最后修改了放弃了家人flag方法。解决代码:
mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
if (isAutoScale == true) {
return true;
}
float x = e.getX();
float y = e.getY();
// Log.e("DoubleTap", getScale() + " , " + initScale);
if (getScale() < SCALE_MID) {
ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MID, x, y), 16);
isAutoScale = true;
} else if (getScale() >= SCALE_MID && getScale() < SCALE_MAX) {
ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MAX, x, y), 16);
isAutoScale = true;
} else {
ZoomImageView.this.postDelayed(new AutoScaleRunnable(initScale, x, y), 16);
isAutoScale = true;
}
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
siglelistener.onSingleClicked();
return super.onSingleTapConfirmed(e);
}
});
onSingleTapConfirmed方法中回调给interface接口,自定义onclick给外部使用。