onKeyDown 和 onKeyLongPress

Posted

技术标签:

【中文标题】onKeyDown 和 onKeyLongPress【英文标题】:onKeyDown and onKeyLongPress 【发布时间】:2012-10-08 15:35:04 【问题描述】:

我希望我的应用程序对音量按钮的正常和长按按键事件做出不同的反应。

我已经看到this,但是如果我一直按住音量按钮,我会在收到KeyLongPressed 事件之前收到很多KeyDown 事件。

我想要一个事件或另一个事件,而不是两者,这样我可以短按调整音量并长按跳过曲目。

你能帮帮我吗?

这是我的代码:

    @Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) 
    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 
    
        Log.d("Test", "Long press!");
        return true;
    
    return super.onKeyLongPress(keyCode, event);


@Override
public boolean onKeyDown(int keyCode, KeyEvent event) 
    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 
        event.startTracking();
        Log.d("Test", "Short");
        return true;
    

    return super.onKeyDown(keyCode, event);

任何帮助表示赞赏! - 虹膜

【问题讨论】:

然后尝试使用 key up (KeyEvent.KEYCODE_VOLUME_UP) 而不是 keydown;如果长按将在按键之前调用,如果长按调用使用标志停止按键操作 那是音量增大键,而不是告诉您该键被按住或类似的指示器。 我现在正在尝试 类似:***.com/questions/19883383/… 【参考方案1】:

这是我写的代码。它就像一个魅力。也许你可以优化它以获得更好的逻辑。但你会明白的。关键是使用标志。 短按是指我们短按音量键并松开。所以 onKeyUp 可以帮助我们检测短按。

package com.example.demo;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;

public class TestVolumeActivity extends Activity 
    boolean flag = false;

    boolean flag2 = false;

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash_screen);
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        getMenuInflater().inflate(R.menu.activity_splash_screen, menu);
        return true;
    

    @Override
    public boolean onKeyLongPress(int keyCode, KeyEvent event) 
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 
            Log.d("Test", "Long press!");
            flag = false;
            flag2 = true;
            return true;
        
        return super.onKeyLongPress(keyCode, event);
    

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) 
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 
            event.startTracking();
            if (flag2 == true) 
                flag = false;
             else 
                flag = true;
                flag2 = false;
            

            return true;
        
        return super.onKeyDown(keyCode, event);
    

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) 
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 

            event.startTracking();
            if (flag) 
                Log.d("Test", "Short");
            
            flag = true;
            flag2 = false;
            return true;
        

        return super.onKeyUp(keyCode, event);
    

Logcat 适用于所有长按(未检测到短按):

10-18 02:06:15.369: D/Test(16834): Long press!
10-18 02:06:18.683: D/Test(16834): Long press!
10-18 02:06:21.566: D/Test(16834): Long press!
10-18 02:06:23.738: D/Test(16834): Long press!

适用于所有短按的 Logcat:

10-18 02:07:42.422: D/Test(16834): Short
10-18 02:07:43.203: D/Test(16834): Short
10-18 02:07:43.663: D/Test(16834): Short
10-18 02:07:44.144: D/Test(16834): Short

【讨论】:

+1 领先我一分钟 :) 我虽然出于某种原因他不会通过关键事件 为什么这么多标志,在onKeyDown里面使用if (event.getRepeatCount() == 0) isShortPress = true; else isShortPress = false; @xmen W.K 是的,这肯定可以用更少的标志来完成。它实际上是为了表明你可以使用标志。【参考方案2】:

根据 SDK 处理长按按钮的正确方法。

import android.app.Activity;
import android.util.Log;
import android.view.KeyEvent;


public class TestVolumeActivity extends Activity

    private static final String TAG = TestVolumeActivity.class.getSimpleName();

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) 
        if( keyCode == KeyEvent.KEYCODE_VOLUME_UP || 
            keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
        
            event.startTracking();
            return true;
        
        return super.onKeyDown(keyCode, event);
    

    @Override
    public boolean onKeyLongPress(int keyCode, KeyEvent event)
    
        if(keyCode == KeyEvent.KEYCODE_VOLUME_UP)
            Log.d(TAG, "Long press KEYCODE_VOLUME_UP");
            return true;
        
        else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
            Log.d(TAG, "Long press KEYCODE_VOLUME_DOWN");
            return true;
        
        return super.onKeyLongPress(keyCode, event);
    

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event)
    
        if((event.getFlags() & KeyEvent.FLAG_CANCELED_LONG_PRESS) == 0)
            if(keyCode == KeyEvent.KEYCODE_VOLUME_UP)
                Log.e(TAG, "Short press KEYCODE_VOLUME_UP");
                return true;
            
            else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
                Log.e(TAG, "Short press KEYCODE_VOLUME_DOWN");
                return true;
            
        
        return super.onKeyUp(keyCode, event);
    

【讨论】:

更标准、更简洁。我唯一的问题是我的设备在长按后不久会发出哔哔声,我通过将else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) return true; 添加到onKeyUp 解决了这个问题。【参考方案3】:

当我即将发布我的答案时,我发现有人已经有了某种解决方案......

但这是我的,简单,就像一个魅力。只有一个标志;)

此代码检测短按和长按,当长按发生时不会触发短按!

注意:如果您想要正常的音量上下行为,请将 onKeyPress 方法中的 return true 更改为 super 调用,如下所示:

event.startTracking();
if(event.getRepeatCount() == 0)
    shortPress = true;

//return true;
return super.onKeyDown(keyCode, event);

没有超级调用的代码:

private boolean shortPress = false;

@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) 
    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 
        shortPress = false;
        Toast.makeText(this, "longPress", Toast.LENGTH_LONG).show();
        return true;
    
    //Just return false because the super call does always the same (returning false)
    return false;


@Override
public boolean onKeyDown(int keyCode, KeyEvent event) 
    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 
        if(event.getAction() == KeyEvent.ACTION_DOWN)
            event.startTracking();
            if(event.getRepeatCount() == 0)
                shortPress = true;
            
            return true;
        
    
    return super.onKeyDown(keyCode, event);


@Override
public boolean onKeyUp(int keyCode, KeyEvent event) 
    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 
        if(shortPress)
            Toast.makeText(this, "shortPress", Toast.LENGTH_LONG).show();
         else 
            //Don't handle longpress here, because the user will have to get his finger back up first
        
        shortPress = false;
        return true;
    
    return super.onKeyUp(keyCode, event);

这里的代码是添加了音量增大键,选择你的一边;)

private boolean shortPress = false;

@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) 
    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 
        shortPress = false;
        Toast.makeText(this, "longPress Volume Down", Toast.LENGTH_LONG).show();
        return true;
     else if(keyCode == KeyEvent.KEYCODE_VOLUME_UP)
        shortPress = false;
        Toast.makeText(this, "longPress Volume Up", Toast.LENGTH_LONG).show();
        return true;
    
    //Just return false because the super call does always the same (returning false)
    return false;


@Override
public boolean onKeyDown(int keyCode, KeyEvent event) 
    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) 
        if(event.getAction() == KeyEvent.ACTION_DOWN)
            event.startTracking();
            if(event.getRepeatCount() == 0)
                shortPress = true;
            
            return true;
        
    
    return super.onKeyDown(keyCode, event);


@Override
public boolean onKeyUp(int keyCode, KeyEvent event) 
    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) 
        if(shortPress)
            Toast.makeText(this, "shortPress Volume Down", Toast.LENGTH_LONG).show();
         else 
            //Don't handle longpress here, because the user will have to get his finger back up first
        
        shortPress = false;
        return true;
     else if(keyCode == KeyEvent.KEYCODE_VOLUME_UP)
        if(shortPress)
            Toast.makeText(this, "shortPress Volume up", Toast.LENGTH_LONG).show();
         else 
            //Don't handle longpress here, because the user will have to get his finger back up first
        
        shortPress = false;
        return true;

    
    return super.onKeyUp(keyCode, event);

【讨论】:

这是更好的答案,因为它使用较少的变量和助记符代码。干得好。【参考方案4】:

我不知道这个答案是否会为您的问题提供可接受的解决方案,因为它依赖于持续获得频繁 KeyDown 事件。

您可以尝试记住引发最后一个KeyDown 事件的系统时间(我将其命名为tLast),并忽略所有KeyDown 事件,直到收到KeyLongPressed 事件。

为了获得“正确的”KeyDown 事件(您在上一步中忽略的事件),您可以让一个线程检查当前系统时间与tLast 之间的时间差(我将命名它tDelta) 足够大,不会被视为连续按下。

鉴于在短时间内抛出了很多KeyDown事件,理论上可以确定当事件间隔足够时(tDelta大于固定值)没有连续按下音量按钮)。

这个解决方案的缺点是,如果用户真的快速按下音量按钮(按下之间的tDelta低于用于评估连续按下的固定值),多次按键将被忽略/视为连续按键。

另一个(次要)缺点是在解释常规按键之前会有延迟,因为tDelta 必须大于在评估您是在处理常规按键还是连续按键时使用的固定值按下。

问候,

卢锡安

编辑: 嗯...第二个想法:你不是在使用KeyListener Android 实现吗?

如果您正在使用它,请查看为此定义的 onKeyUp 方法。

我认为如果你只是扩展这个类(或其派生类之一)并使用onKeyUp 方法来确定你是否正在处理连续按下(即按钮的时间)会更优雅被按住大于固定值)。

如果您可以使用此方法,请执行此操作。它也比上面介绍的解决方法更高效、更易于维护和更直接。

KeyListener Javadoc

【讨论】:

以上是关于onKeyDown 和 onKeyLongPress的主要内容,如果未能解决你的问题,请参考以下文章

onkeydown 和 onkeyup 事件在 Internet Explorer 8 上不起作用

onkeydown-onkeypress-onkeyup

android onKeyDown中true和false的问题

怎么在JS里面设置自动出发onkeydown()事件,例如当用户输入的商品件数达到10件就自动触发提交按钮。

Sencha touch 中的 onkeydown

javascript onkeydown 为啥只能执行一次,再次触发却无效了呢?