在我的应用程序中,我需要处理移动和点击事件。
单击是一个ACTION_DOWN操作的序列,几个ACTION_MOVE操作和一个ACTION_UP操作。理论上,如果您获得ACTION_DOWN事件然后获得ACTION_UP事件 - 这意味着用户刚刚单击了您的视图。
但实际上,这个序列在某些设备上不起作用。在我的三星Galaxy Gio上,只需单击我的视图:ACTION_DOWN,几次ACTION_MOVE,然后ACTION_UP即可获得此类序列。即我使用ACTION_MOVE操作代码获得了一些无法预料的OnTouchEvent触发。我从未(或几乎从未)获得序列ACTION_DOWN - > ACTION_UP。
我也不能使用OnClickListener,因为它没有给出点击的位置。那么如何检测点击事件并将其与移动区分开来呢?
答案 0 :(得分:92)
这是另一个非常简单的解决方案,不需要担心手指被移动。如果您只是根据移动的距离进行点击,那么如何区分点击和长按。
你可以把更多的智能放入其中并包括移动的距离,但是当用户在200毫秒内移动的距离应该构成移动而不是点击时,我还没遇到过实例。
setOnTouchListener(new OnTouchListener() {
private static final int MAX_CLICK_DURATION = 200;
private long startClickTime;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
startClickTime = Calendar.getInstance().getTimeInMillis();
break;
}
case MotionEvent.ACTION_UP: {
long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
if(clickDuration < MAX_CLICK_DURATION) {
//click event has occurred
}
}
}
return true;
}
});
答案 1 :(得分:49)
考虑到这一点,我得到了最好的结果:
ACTION_DOWN
和ACTION_UP
事件之间移动。我想在density-indepenent pixels而不是像素中指定最大允许距离,以更好地支持不同的屏幕。例如, 15 DP 。示例:
/**
* Max allowed duration for a "click", in milliseconds.
*/
private static final int MAX_CLICK_DURATION = 1000;
/**
* Max allowed distance to move during a "click", in DP.
*/
private static final int MAX_CLICK_DISTANCE = 15;
private long pressStartTime;
private float pressedX;
private float pressedY;
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN: {
pressStartTime = System.currentTimeMillis();
pressedX = e.getX();
pressedY = e.getY();
break;
}
case MotionEvent.ACTION_UP: {
long pressDuration = System.currentTimeMillis() - pressStartTime;
if (pressDuration < MAX_CLICK_DURATION && distance(pressedX, pressedY, e.getX(), e.getY()) < MAX_CLICK_DISTANCE) {
// Click event has occurred
}
}
}
}
private static float distance(float x1, float y1, float x2, float y2) {
float dx = x1 - x2;
float dy = y1 - y2;
float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
return pxToDp(distanceInPx);
}
private static float pxToDp(float px) {
return px / getResources().getDisplayMetrics().density;
}
这里的想法与Gem's solution中的想法相同,但存在以下差异:
更新(2015年):还可以查看Gabriel's fine-tuned version of this。
答案 2 :(得分:26)
考虑Jonik's lead我构建了一个稍微精细的调整版本,如果你移动手指然后在放手之前返回现场,则不会注册为点击:
所以这是我的解决方案:
/**
* Max allowed duration for a "click", in milliseconds.
*/
private static final int MAX_CLICK_DURATION = 1000;
/**
* Max allowed distance to move during a "click", in DP.
*/
private static final int MAX_CLICK_DISTANCE = 15;
private long pressStartTime;
private float pressedX;
private float pressedY;
private boolean stayedWithinClickDistance;
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN: {
pressStartTime = System.currentTimeMillis();
pressedX = e.getX();
pressedY = e.getY();
stayedWithinClickDistance = true;
break;
}
case MotionEvent.ACTION_MOVE: {
if (stayedWithinClickDistance && distance(pressedX, pressedY, e.getX(), e.getY()) > MAX_CLICK_DISTANCE) {
stayedWithinClickDistance = false;
}
break;
}
case MotionEvent.ACTION_UP: {
long pressDuration = System.currentTimeMillis() - pressStartTime;
if (pressDuration < MAX_CLICK_DURATION && stayedWithinClickDistance) {
// Click event has occurred
}
}
}
}
private static float distance(float x1, float y1, float x2, float y2) {
float dx = x1 - x2;
float dy = y1 - y2;
float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
return pxToDp(distanceInPx);
}
private static float pxToDp(float px) {
return px / getResources().getDisplayMetrics().density;
}
答案 3 :(得分:14)
使用探测器,它有效,拖动时不会升起
字段:
private GestureDetector mTapDetector;
初始化:
mTapDetector = new GestureDetector(context,new GestureTap());
内班:
class GestureTap extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// TODO: handle tap here
return true;
}
}
onTouch:
@Override
public boolean onTouch(View v, MotionEvent event) {
mTapDetector.onTouchEvent(event);
return true;
}
享受:)
答案 4 :(得分:6)
要获得最佳的点击事件识别我们必须考虑两件事:
实际上我结合了Stimsoni和Neethirajan给出的逻辑
所以这是我的解决方案:
view.setOnTouchListener(new OnTouchListener() {
private final int MAX_CLICK_DURATION = 400;
private final int MAX_CLICK_DISTANCE = 5;
private long startClickTime;
private float x1;
private float y1;
private float x2;
private float y2;
private float dx;
private float dy;
@Override
public boolean onTouch(View view, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
startClickTime = Calendar.getInstance().getTimeInMillis();
x1 = event.getX();
y1 = event.getY();
break;
}
case MotionEvent.ACTION_UP:
{
long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
x2 = event.getX();
y2 = event.getY();
dx = x2-x1;
dy = y2-y1;
if(clickDuration < MAX_CLICK_DURATION && dx < MAX_CLICK_DISTANCE && dy < MAX_CLICK_DISTANCE)
Log.v("","On Item Clicked:: ");
}
}
return false;
}
});
答案 5 :(得分:4)
下面的代码将解决您的问题
@Override public boolean onTouchEvent(MotionEvent event) { switch(event.getAction()) { case(MotionEvent.ACTION_DOWN): x1 = event.getX(); y1 = event.getY(); break; case(MotionEvent.ACTION_UP): { x2 = event.getX(); y2 = event.getY(); dx = x2-x1; dy = y2-y1; if(Math.abs(dx) > Math.abs(dy)) { if(dx>0) move(1); //right else if (dx == 0) move(5); //click else move(2); //left } else { if(dy>0) move(3); // down else if (dy == 0) move(5); //click else move(4); //up } } } return true; }
答案 6 :(得分:3)
如果没有发生ACTION_MOVE,ACTION_DOWN很难发生。屏幕上的最轻微抽搐在与第一次触摸发生位置不同的位置将触发MOVE事件。此外,我相信手指压力的变化也会触发MOVE事件。我会在Action_Move方法中使用if语句来尝试确定从原始DOWN运动开始移动的距离。如果移动发生在某个设定半径之外,则会发生MOVE操作。它可能不是最好的,资源有效的方式来做你尝试但它应该工作。
答案 7 :(得分:1)
如果您只想点击,请使用:
// remove the ball from its current parent
fewerColorsPowerupIcon.removeFromParent()
// add it the scene
self.addChild(fewerColorsPowerupIcon)
// place the ball of the screen so that we can bring it on later
fewerColorsPowerupIcon.position = CGPointMake((width * -0.1) , (height * -0.1))
// set the size of the icon
fewerColorsPowerupIcon.xScale = scaleFactor
fewerColorsPowerupIcon.yScale = scaleFactor
答案 8 :(得分:1)
添加上述答案,如果你想同时实现onClick和Drag操作,那么下面我的代码可以。从@Stimsoni获得一些帮助:
try{
...
datenbankverbindung = DriverManager.getConnection(link,connectionProperties);
}catch(SQLException e){
...//do whatever you want
}
答案 9 :(得分:1)
使用Gil SH答案,我通过实施onSingleTapUp()
而不是onSingleTapConfirmed()
来改进它。如果拖动/移动它会更快并且不会单击视图。
GestureTap:
public class GestureTap extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
button.performClick();
return true;
}
}
使用它像:
final GestureDetector gestureDetector = new GestureDetector(getApplicationContext(), new GestureTap());
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
gestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_UP:
return true;
case MotionEvent.ACTION_MOVE:
return true;
}
return false;
}
});