138

Android 拦截返回键事件的实例详解

 5 years ago
source link: http://blog.uiuno.com/2018/07/07/18/00/03/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

KeyEvent类

Android.View.KeyEvent类中定义了一系列的常量和方法,用来描述Android中的按键事件。

和返回键有关的常量和方法有。

KeyEvent.KEYCODE_BACK: 表示key类型为返回键

KeyEvent.ACTION_DOWN:表示事件为按下key,如果一直按住不放,则会不停产生此事件。

KeyEvent.ACTION_UP:表示事件为为放开key,一次点击key过程只会调用一次。

public final int getKeyCode():获取此事件对应的key类型。

public final int getAction():获取此事件对应的事件类型

Activity中拦截返回键

在Activity的派生类中可以通过重写onKeyDown和onKeyUp这两个方法来拦截返回键。这两个方法的原型为。

public boolean onKeyDown(int keyCode, KeyEvent event);
public boolean onKeyUp(int keyCode, KeyEvent event);

这两个方法都有两个参数,第一个参数为keyCode,即此事件对应的key类型。第二个参数为此事件对象,

通过event可以获取到事件的详细信息。onKeyDown()方法中event.getAction()返回的始终是KeyEvent.ACTION_DOWN,onKeyUp()方法中event.getAction()返回的始终是KeyEvent.ACTION_UP。

如果要拦截返回键,则在两个方法中加入如下代码。

if (keyCode == KeyEvent.KEYCODE_BACK) {
    ...
}

Dialog中拦截返回键

在Dialog中可以通过调用setOnKeyListener()方法来为Dialog增加按键事件的监听。

setOnKeyListener()方法原型为:

public void setOnKeyListener(final OnKeyListener onKeyListener);

此方法有一个参数,参数需要实现OnKeyListener接口。OnKeyListener接口定义如下。

interface OnKeyListener {
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event);
}

onKey()方法包含三个参数,第一个参数是拦截到此事件的对话框对象的引用。第二个参数是此事件对应的keyCode,第三个参数是此事件对象本身。

如果要拦截返回键,则在Dialog中加入如下代码。

setOnKeyListener(new OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK 
            && event.getAction() == KeyEvent.ACTION_UP) {
            ...
        }
        return false;
    }
});

EditText中拦截返回键事件

在EditText中同样可以通过调用setOnKeyListener()方法来为EditText增加按键事件的监听。

setOnKeyListener()方法的使用和Dialog中完全相同。

View中拦截返回键事件

在所有View的派生类对象上都可以调用setOnKeyListener()方法来增加按键事件的监听,不过除了EditText之外,其他View设置了监听并不会起到作用。按键事件产生时并不会分发到View上。

多个拦截事件的冲突与选择

目前在Activity,Dialog和EditText中都可以成功设置拦截事件。如果多个对象设置了拦截事件。则事件只会分发到一个对象上。

通过实验得到如下结论:

1、Dialog优先级最高,如果有一个Activity,Activity中弹出一个Dialog,Dialog中有一个EditText,在Activity,Dialog和EditText中都设置监听,只有Dialog中设置的监听过程能够正确执行。Activity和EditText中的监听过程无法被执行到。

2、Activity优先级次于Dialog,但高于EditText,如果有一个Activity,Activity中有一个EditText,在Activity和EditText中都设置监听,只有Activity中设置的监听过程能够正确执行。EditText中的监听过程无法被执行到。

3、如果当前界面中有PopupWindow,则按返回键后PopupWindow会收到事件通知,并消费(执行dismiss();)。其他设置了监听的对象无法获取到事件通知。(原因是PopupWindow内部布局类PopupViewContainer重写了dispatchKeyEvent()方法)

返回键响应速度限制

当用户在按返回键后,如果界面出现卡顿,导致界面没有立刻完成返回动作,这时用户可能觉得是按下操作没有成功,又再一次按下返回键。这会导致返回事件又一次被调用。当卡顿结束后就出现多次返回的现象。为了避免这种情况出现,可以在拦截返回键的函数中增加时间限制。即如果本次返回事件距离上次处理时间过段,则不处理本次事件。直接return true;消费此次事件。

以对话框中拦截返回键举例,增加返回键响应速度限制的代码如下。

setOnKeyListener(new OnKeyListener() {
    private static final int INTERVAL = 500;   //响应间隔时间
    private long lastReturnTime;               //上次响应返回事件时间
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK 
            && event.getAction() == KeyEvent.ACTION_UP) {
            long curTime = System.currentTimeMillis();
            if (curTime - lastReturnTime > INTERVAL) {
                lastReturnTime = curTime;
                ...
            } else {
                return true;
            }
        }
        return false;
    }
});

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK