Java 检测触摸按压vs长按压vs移动?

Java 检测触摸按压vs长按压vs移动?,java,android,touch,move,long-press,Java,Android,Touch,Move,Long Press,我目前正忙于Android编程,但我在检测不同的触摸事件时遇到了一个小问题,即正常的触摸按键(按下屏幕并立即释放)、长按(触摸屏幕并按住手指)和移动(在屏幕上拖动) 我想做的是在我的屏幕上有一个(圆的)图像,我可以拖动它。然后,当我按一次(短按/普通按)时,会出现一个祝酒词,上面有一些关于它的基本信息。当我长按它时,会出现一个带有列表的AlertDialog来选择不同的图像(圆形、矩形或三角形) 我用自己的OnTouchListener创建了一个自定义视图,用于检测事件并在onDraw中绘制图像

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

我想做的是在我的屏幕上有一个(圆的)图像,我可以拖动它。然后,当我按一次(短按/普通按)时,会出现一个祝酒词,上面有一些关于它的基本信息。当我长按它时,会出现一个带有列表的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;
}
问题是,按键并没有像预期的那样工作,因为当我随意触摸屏幕时,它也会检测到一点移动,并取消触摸按键,转而在图像周围移动

我引入了一个新的变量“mTouchDelay”,我在操作时将其设置为0,在移动中增加,如果在移动中大于等于3,则执行我的“移动”代码。但我有一种感觉,这不是真正的方式去

我还没有发现如何检测长按。真正的罪魁祸首是似乎总是触发的行动

有关我大致想要的示例,请参见Android应用程序“DailyStrip”:它显示一幅漫画的图像。如果屏幕太大,你可以拖动它。您可以点击它一次以弹出一些控件,然后长按它以显示选项菜单


另外,我正试图让它在安卓1.5上运行,因为我的手机只在安卓1.5上运行。

来自安卓文档-

onLongClick() 从View.OnLongClickListener。当用户触摸并按住项目(处于触摸模式时),或使用导航键或轨迹球聚焦项目并按住适当的“回车”键或按住轨迹球(一秒钟)时,调用此选项

onTouch() 从View.OnTouchListener。当用户执行符合触摸事件条件的操作时,会调用此操作,包括按下、释放或屏幕上的任何移动手势(在项目范围内)


至于“即使在我触摸时也会发生移动”,我会设置一个增量,并确保在输入移动代码之前视图至少移动了增量。如果没有,请启动触摸代码。

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

在初始化您的活动时:

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);

我一直在寻找类似的解决方案,这就是我的建议。 在OnTouch方法中,记录MotionEvent.ACTION\u DOWN事件的时间,然后再次记录MotionEvent.ACTION\u UP事件的时间。这样,您也可以设置自己的阈值。经过几次实验后,你会知道记录一次简单的触摸所需的最大时间(毫秒),你可以在移动或其他方式中使用它


希望这有帮助。如果您使用了不同的方法并解决了您的问题,请发表评论。

我认为您应该实现GestureDetector.OnTestureListener 如和中所述
然后在onSingleTapUp中实现tap逻辑,在onScroll事件中实现move逻辑

在希望longclick不以click事件结束后,我正在处理这个混乱

这就是我所做的

public boolean onLongClick(View arg0) {
    Toast.makeText(getContext(), "long click", Toast.LENGTH_SHORT).show();
    longClicked = true;
    return false;
}

public void onClick(View arg0) {
    if(!longClicked){
        Toast.makeText(getContext(), "click", Toast.LENGTH_SHORT).show();
    }
    longClick = false; // sets the clickability enabled
}

boolean longClicked = false;

这有点像黑客,但它可以工作。

它只需要在overlay类中使用一个ontouch事件。检查这个,它帮助了我


此代码可以区分单击和移动(拖动、滚动)。在onTouchEvent中,设置一个标志isOnClick,并在操作上设置初始X、Y坐标。清除动作移动时的标志(注意经常检测到无意移动,这可以通过阈值常量解决)

如上所述,对于LongPress,GestureDetector是一个不错的选择。检查此问答:


如果需要区分单击、长按和滚动,请使用手势检测器

活动实现了
GestureDetector.OnTestureListener

例如,在onCreate中创建检测器

mDetector = new GestureDetectorCompat(getActivity().getApplicationContext(),this);
然后选择在视图(例如webview)上设置TouchListener,其中


现在,您可以使用Override onScroll、onFling、showPress(检测长按)或onSingleTapUp(检测单击)

GestureDetector.SimpleOnGestureListener在这三种情况下都有帮助的方法

   GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {

        //for single click event.
        @Override
        public boolean onSingleTapUp(MotionEvent motionEvent) {
            return true;
        }

        //for detecting a press event. Code for drag can be added here.
        @Override
        public void onShowPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData clipData = ClipData.newPlainText("..", "...");
            clipboardManager.setPrimaryClip(clipData);

            ConceptDragShadowBuilder dragShadowBuilder = new CustomDragShadowBuilder(child);
            // drag child view.
            child.startDrag(clipData, dragShadowBuilder, child, 0);
        }

        //for detecting longpress event
        @Override
        public void onLongPress(MotionEvent e) {
            super.onLongPress(e);
        }
    });

用onLongClick和longclick的“那种”效果不错,但我仍然面临两个问题。首先,onLongClick触发两次长时间单击(我只需显示一个Toast并返回true,我得到两个Toast)。而且,当我按住时,我会在按住的同时得到长时间的点击,但当我松开时,我仍然会从onTouch中得到动作。我怎样才能防止onLongClick触发后的操作发生?双击onLongClick让我担心,我不知道为什么会触发两次。至于仍在发射的动作,我想问你为什么需要追踪动作向上和向下。测试onLongClick()被激发时onTouch()是否被激发。如果不是,我不确定你是否需要捕捉这些。您应该只需要在实际触摸项目和移动项目时使用onTouch()。您还可以查看将onClick()用于“onTouch()”和仅将onTouch()用于移动。但不确定这是否满足您的要求。这需要一个Java标记。然而,如果你曾经在一个可以通过jQuery访问的web应用程序中发现了这一点,那么我也在试图找出如何拦截长点击(点击保持,长按)的方法?抱歉,这里是新手。哦,如果我被发送了一个事件,我可以“消费”它,这意味着其他正在监听同一事件的钩子也不会被调用。例如,当我把手从屏幕上举起时,可能会沿着组件层次结构发送一条“UP”消息,除非我使用它。我看到了。我原则上理解你写的东西,但是你实际上是如何“消费”的,比如说,“上升”事件?啊-消费
onTouch(View v, MotionEvent event) {
return mDetector.onTouchEvent(event);
}
   GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {

        //for single click event.
        @Override
        public boolean onSingleTapUp(MotionEvent motionEvent) {
            return true;
        }

        //for detecting a press event. Code for drag can be added here.
        @Override
        public void onShowPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData clipData = ClipData.newPlainText("..", "...");
            clipboardManager.setPrimaryClip(clipData);

            ConceptDragShadowBuilder dragShadowBuilder = new CustomDragShadowBuilder(child);
            // drag child view.
            child.startDrag(clipData, dragShadowBuilder, child, 0);
        }

        //for detecting longpress event
        @Override
        public void onLongPress(MotionEvent e) {
            super.onLongPress(e);
        }
    });