需求再现
最近在开发这样一个需求:做一个悬浮的按钮,长按可以拖动按钮移动,点击要能跳转。
需求分析
点击事件处理,使用View.OnClickListener事件处理即可;
拖动功能需要重写View.OnTouchListener事件即可;
开始代码大致如下:
View movedButton; //需要移动的按钮
movedButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//在这里处理点击跳转
}
});
movedButton.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
}else if (event.getAction() == MotionEvent.ACTION_MOVE) {
//处理移动
v.offsetLeftAndRight(offsetX);
v.offsetTopAndBottom(offsetY);
}else if (event.getAction() == MotionEvent.ACTION_UP) {
}
return false;
}
});
遇到的问题
在测试的过程中发现,按钮确实可以正常移动,可是每次移动都会触发按钮的点击事件,一瞬间我就想到了可能是事件冲突导致的,于是查看了一下View的源代码(此处不贴源代码了,只说明问题原因),发现onTouch事件是最先触发的,在MotionEvent.ACTION_UP的时候才触发了onClick事件及onLongClick事件。也就是说,需要在ACTION_UP的时候判定是否要消费此次事件,如果消费掉就返回true,那么就不会触发onClick事件了。
解决方案
我们可以设定一个布尔变量标记触摸事件过程中是否有移动即可,代码如下:
View movedButton; //需要移动的按钮
movedButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//在这里处理点击跳转
}
});
movedButton.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean hasMoved;
if (event.getAction() == MotionEvent.ACTION_DOWN) {
hasMoved = false;
}else if (event.getAction() == MotionEvent.ACTION_MOVE) {
//处理移动
v.offsetLeftAndRight(offsetX);
v.offsetTopAndBottom(offsetY);
//注意:将小幅度的移动判定为点击事件,这样可以增加点击事件的灵敏度
if(Math.abs(offsetX) > 5 || Math.abs(offsetY) > 5) {
hasMoved = true;
}
}else if (event.getAction() == MotionEvent.ACTION_UP) {
return hasMoved;
}
return false;
}
});
小结一下
1、事件处理贯穿整个Android应用,使用过程中时刻牢记Android事件的处理机制,所有的事件都是用onTouch事件开始的。
2、本例子中,将小幅度的移动判定为点击事件,这样可以增加点击事件的灵敏度,体验会更好一些。