Android focusableInTouchMode需要触犯两次才能点击

在Android开发中,有时我们会遇到一个奇怪的问题,就是当一个View设置了focusableInTouchMode属性为true后,需要点击两次才能获取焦点。这种情况下,一般来说,我们期望只需要点击一次就能获取焦点。那么,为什么会出现这种情况呢?本文将详细介绍这个问题的原因和解决方法,并提供相应的代码示例。

问题的原因

在Android中,当一个View设置了focusableInTouchMode属性为true后,这个View可以在触摸模式下获取焦点。但是,为什么会出现需要点击两次才能获取焦点的情况呢?

这是因为,当我们点击一个View时,系统会根据点击位置判断是否需要将焦点给这个View,如果需要将焦点给这个View,那么就会调用这个View的onTouchEvent方法来处理触摸事件。而在onTouchEvent方法中,会根据一些条件判断是否需要将焦点给这个View。其中,有一个关键条件是:在ACTION_DOWN事件中,如果这个View是可以获取焦点的,并且这个View没有获取到焦点时,那么就会将焦点给这个View,并返回true,表示事件已处理。而在ACTION_UP事件中,如果这个View已经获取到焦点,那么就会处理点击事件。

所以,当一个View设置了focusableInTouchMode属性为true时,在ACTION_DOWN事件中,这个View会获取到焦点,但是在ACTION_UP事件中,由于这个View已经获取到焦点了,所以就不会处理点击事件,这就导致了需要点击两次才能获取焦点的问题。

解决方法

要解决这个问题,我们可以使用以下两种方法:

  1. ACTION_DOWN事件中,将焦点给其他的View,然后在ACTION_UP事件中再将焦点还给目标View。这样,由于目标View在ACTION_UP事件中没有焦点,所以会处理点击事件。示例代码如下:
view.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 将焦点给其他的View
                otherView.requestFocus();
                break;
            case MotionEvent.ACTION_UP:
                // 将焦点还给目标View
                view.requestFocus();
                break;
        }
        return true;
    }
});
  1. ACTION_DOWN事件中,将目标View设置为不可获取焦点,然后在ACTION_UP事件中再将其设置为可获取焦点。这样,在ACTION_UP事件中,如果这个View已经获取到焦点,那么就会处理点击事件。示例代码如下:
view.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 将View设置为不可获取焦点
                view.setFocusableInTouchMode(false);
                break;
            case MotionEvent.ACTION_UP:
                // 将View设置为可获取焦点
                view.setFocusableInTouchMode(true);
                break;
        }
        return true;
    }
});

结语

在Android开发中,当一个View设置了focusableInTouchMode属性为true后,需要点击两次才能获取焦点的问题是比较常见的。通过本文的介绍,我们了解到这个问题的原因是因为在ACTION_DOWN事件中,这个View会获取到焦点,但是在ACTION_UP事件中,已经获取到焦点的View不会处理点击事件。为了解决这个问题,我们可以使用两种方法:在ACTION_DOWN事件中,将焦点给其他的View,然后在ACTION_UP事件中再将焦点还给目标View;或者在ACTION_DOWN事件中,将目标View设置为不可获取焦点,然后在ACTION_UP事件中再将其设置为可获取焦点。