【问题标题】:Why android onLongPress always is fired after onDoubleTap?为什么android onLongPress总是在onDoubleTap之后被解雇?
【发布时间】:2011-11-28 05:55:05
【问题描述】:

根据此代码,我在按钮上放置了 onLongPress 和 onDoubleTap 操作:

...
GestureDetector detector = new GestureDetector(this, new TapDetector());

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main); 
    detector = new GestureDetector(this, new TapDetector());
    ... 
}

private class TapDetector extends GestureDetector.SimpleOnGestureListener { 

    @Override
    public boolean onDoubleTap(MotionEvent e) {
        // Do something
        return true;
    }

    @Override
     public void onLongPress(MotionEvent e) {          
        // Do something          
    }
}

Button incomeButton = (Button) findViewById(R.id.income);
button.setOnTouchListener(new OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        detector.onTouchEvent(event);
        return true;
    }
});

我总是看到 onLongPress 在 onDoubleClick 触发和执行后触发。这种违反直觉的行为的原因是什么,如何避免?

更新 我已将源代码更改为更具体

public class MainActivity extends Activity { 
private GestureDetector detector;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main); 
    detector = new GestureDetector(this, new TapDetector());    

    Button button = (Button) findViewById(R.id.button);                 
    button.setOnTouchListener(new OnTouchListener(){
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            System.out.println("************* onTouch *************");
            detector.onTouchEvent(event);
            return true;
        }
    });                        
}       

class TapDetector extends GestureDetector.SimpleOnGestureListener {  

    @Override
     public void onLongPress(MotionEvent e) {
        System.out.println("************* onLongPress *************");                    
    }         

    @Override
     public boolean onDoubleTap(MotionEvent e) {
        System.out.println("************* onDoubleTap *************");  
        Intent intent = new Intent();        
        intent.setClass(getApplicationContext(), NewActivity.class);
        intent.putExtra("parameterName", "parameter");
        startActivity(intent);              
        return true;
    }             
}        
}

这是我点击onDoubleTap后的日志。你可以在最后看到 onLongPress - 我从不点击它。

I/System.out( 1106): ************* onTouch *************
I/System.out( 1106): ************* onTouch *************
I/System.out( 1106): ************* onTouch *************
I/System.out( 1106): ************* onDoubleTap *************
I/ActivityManager(   59): Starting activity: Intent { cmp=my.tapdetector/.NewActivity (has extras) }
I/ActivityManager(   59): Displayed activity my.tapdetector/.NewActivity: 324 ms (total 324 ms)
I/System.out( 1106): ************* onLongPress *************

更新我找到了解决方案。为避免 onLongPress 触发 两个 需要进行更改:

首先:detector.setIsLongpressEnabled(true);在 onTouch(View v, MotionEvent 事件)

    button.setOnTouchListener(new OnTouchListener(){
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            System.out.println("************* onTouch *************");
            detector.onTouchEvent(event);
            detector.setIsLongpressEnabled(true);
            return true;
        }
    });

第二:添加detector.setIsLongpressEnabled(false);在 onDoubleTap(MotionEvent e)

     public boolean onDoubleTap(MotionEvent e) {
        detector.setIsLongpressEnabled(false);
        System.out.println("************* onDoubleTap *************");  
        Intent intent = new Intent();        
        intent.setClass(getApplicationContext(), NewActivity.class);
        intent.putExtra("parameterName", "parameter");
        startActivity(intent);             
        return true;
    }

【问题讨论】:

  • 不能重复,抱歉。在这两个事件上使用 Log.i(),它们被正确调用。
  • 像已接受答案的 cmets 中所述的内置竞争条件的解决方法也不错。谢谢。

标签: android double-click


【解决方案1】:

从技术上讲,这不应该发生

case MotionEvent.ACTION_DOWN:
        mLastMotionX = x;
        mLastMotionY = y;
        mCurrentDownEvent = MotionEvent.obtain(ev);
        mAlwaysInTapRegion = true;
        mInLongPress = false;

        if (mIsLongpressEnabled) {
            mHandler.removeMessages(LONG_PRESS);
            mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
                    + tapTime + longpressTime);
        }
        mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + tapTime);

因为在 ACTION_DOWN 或 ACTION_UP 事件上,所有 LONG_PRESS 消息事件都从队列中删除。因此,在第二次点击时,以下代码将删除长按事件。

 mHandler.removeMessages(LONG_PRESS);

忍者编辑:解决您的问题的 hacky 解决方法

     @Override
     public void onLongPress(MotionEvent e) {
        if(MainActivity.this.hasWindowFocus())
        {
            Log.d("Touchy", "Long tap");    
        }
    }

【讨论】:

  • 正如我刚刚发现的,如果在 onDoubleClick 方法上设置了断点,我总是在 onDoubleTap 仅在调试器下之后触发 onLongPress。如果我删除断点 - 一切都好......
  • 那么有道理,mCurrentDownEvent.getDownTime() + tapTime + longpressTime 到时候已经过期了
  • 看来如果我在 onDoubleTap 方法中长时间处理正文,我总是会被 onLongPress 解雇?
  • 嗯...所以,如果我需要在 onDoubleTap 方法中长时间处理,我应该怎么做才能避免 onLongPress 触发!?
  • 由于您无权访问mHandler,因此您无能为力。改用 Logcat 进行调试。
【解决方案2】:

您总是会看到 onLongPress 被触发,因为在您的代码中,您在使用 onDoubleTap 事件之前启动了一个意图。
您可以通过
public void setIsLongpressEnabled (boolean isLongpressEnabled)
禁用 onLongPress 并使用 onDown 方法执行您的操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-01
    • 2011-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多