检测触摸按压与长按vs运动?

pbe*_*ean 65 java android move touch long-press

我目前正在摆弄Android编程,但我在检测不同的触摸事件时遇到一个小问题,即正常触摸按下(按下屏幕并立即释放),长按(触摸屏幕并按住手指) )和移动(在屏幕上拖动).

我想要做的是在屏幕上有一个图像(圆圈),我可以拖动它.然后,当我按一次(短/正常按下)时,Toast会提供一些关于它的基本信息.当我长按它时,会出现一个带有列表的AlertDialog来选择不同的图像(圆形,矩形或三角形).

我使用自己的OnTouchListener创建了一个自定义视图来检测事件并在onDraw中绘制图像.OnTouchListener.onTouch是这样的:

// has a touch press started?
private boolean touchStarted = false;
// co-ordinates of image
private int x, y;

public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN) {
        touchStarted = true;
    }
    else if (action == MotionEvent.ACTION_MOVE) {
        // movement: cancel the touch press
        touchStarted = false;

        x = event.getX();
        y = event.getY();

        invalidate(); // request draw
    }
    else if (action == MotionEvent.ACTION_UP) {
        if (touchStarted) {
            // touch press complete, show toast
            Toast.makeText(v.getContext(), "Coords: " + x + ", " + y, 1000).show();
        }
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

问题是印刷机没有按预期工作,因为当我随便触摸屏幕时,它还会检测到一点点移动并取消触摸按压并在图像周围移动.

我在这周围"乱砍"我引入一个新的变量"mTouchDelay",我在ACTION_DOWN上设置为0,在MOVE中增加,如果在MOVE中它> = 3,我执行我的"移动"代码.但我觉得这不是真正的方法.

我还没有发现如何检测长按.罪魁祸首真的是MOVE,似乎总是触发.

有关我大概需要的示例,请参阅Android应用程序"DailyStrip":它显示漫画的图像.如果它对于屏幕而言太大,您可以拖动它.您可以点击一次以使某些控件弹出,然后长按它以显示选项菜单.

PS.我试图让它在Android 1.5上运行,因为我的手机只运行1.5.

MSq*_*are 93

此代码可以区分单击和移动(拖动,滚动).在onTouchEvent中设置一个标志isOnClick,并在ACTION_DOWN上设置初始X,Y坐标.清除ACTION_MOVE上的标志(注意经常检测到无意识的移动,可以用THRESHOLD const解决).

private float mDownX;
private float mDownY;
private final float SCROLL_THRESHOLD = 10;
private boolean isOnClick;

@Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            mDownX = ev.getX();
            mDownY = ev.getY();
            isOnClick = true;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            if (isOnClick) {
                Log.i(LOG_TAG, "onClick ");
                //TODO onClick code
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (isOnClick && (Math.abs(mDownX - ev.getX()) > SCROLL_THRESHOLD || Math.abs(mDownY - ev.getY()) > SCROLL_THRESHOLD)) {
                Log.i(LOG_TAG, "movement detected");
                isOnClick = false;
            }
            break;
        default:
            break;
    }
    return true;
}
Run Code Online (Sandbox Code Playgroud)

对于上面建议的LongPress,GestureDetector是可行的方法.查看此问答:

使用Android检测长按

  • 这非常有效.对我来说唯一的事情是,我需要在拖动期间(当手指移动时)也获得事件.此代码仅为整个拖动期间的移动提供一个事件.要获得所需的事件,删除"isOnClick &&"部分就可以了. (5认同)
  • `&MotionEvent.ACTION_MASK`做什么? (2认同)

Jas*_* L. 21

来自Android文档 -

onLongClick()

从View.OnLongClickListener.当用户触摸并保持项目时(当处于触摸模式时)或者使用导航键或轨迹球聚焦于项目并按下并按住合适的"输入"键或按下并按住轨迹球时(一秒钟).

onTouch()

从View.OnTouchListener.当用户执行限定为触摸事件的动作时调用此方法,包括按下,释放或屏幕上的任何移动手势(在项目的范围内).

至于"即使我触摸时也会发生移动",我会设置一个三角形,并确保在移动代码之前,视图已被移动了至少三角形.如果还没有,请启动触摸代码.


San*_*har 15

经过大量的实验,我发现了这一点.

在您的活动初始化中:

setOnLongClickListener(new View.OnLongClickListener() {
  public boolean onLongClick(View view) {
    activity.openContextMenu(view);  
    return true;  // avoid extra click events
  }
});
setOnTouch(new View.OnTouchListener(){
  public boolean onTouch(View v, MotionEvent e){
    switch(e.getAction & MotionEvent.ACTION_MASK){
      // do drag/gesture processing. 
    }
    // you MUST return false for ACTION_DOWN and ACTION_UP, for long click to work
    // you can return true for ACTION_MOVEs that you consume. 
    // DOWN/UP are needed by the long click timer.
    // if you want, you can consume the UP if you have made a drag - so that after 
    // a long drag, no long-click is generated.
    return false;
  }
});
setLongClickable(true);
Run Code Online (Sandbox Code Playgroud)

  • 哦 - 如果我发送了一个事件,我可以"消耗"它,这意味着其他正在侦听同一事件的钩子也不会被调用.例如,当我从屏幕上抬起手时,除非我使用它,否则可以沿组件层次结构发送"UP"消息. (2认同)