EditText: android:focusable和android:focusableInTouchMode的区别

android:focusable
之所以有这个属性主要是因为Android系统不仅仅是针对手机的,有可能在电视、手表等等的非触摸输入设备上(如Android TV),这些设备只有物理上下键不具备触摸功能,
那么当把这个属性值设置为true的时候,比方说你按了一下向下键,屏幕上的内容就会对应选中一个向下的控件(如果这个控件设置android:focusable = true的话),否则
就会选中下一个具备focusable能力的控件。


android:focusableInTouchMode
与上面那种情况相反,如果是针对手机开发的话,那么大部分手机都具备触摸功能,那么这个属性有什么作用呢?
从交互的角度上讲,焦点的作用其实就是为了提示用户当前控件已被选中了,可以进行下一步的操作。比如在Android 5.0上新推出的Material Design效果上面,如果一个EditText被选中了,那么它的
输入框就会更换颜色以示区别。但是在手机开发中并不是所有的控件都需要有选中这种状态,通常在点击后可能只想达到某种效果(如点击按钮就是想触发点击事件,不需要有选中效果),那么这个时候
如果把focusableInTouchMode设置为true,此时执行的就是更换焦点操作,相应的事件就无法及时得到响应,这样的体验就很不好。
例:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ddffff"
    android:gravity="center"
    android:orientation="vertical"
    android:focusableInTouchMode="true"
    >

    <View
        android:id="@+id/view_test"
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:focusableInTouchMode="true"
        android:background="#ff0000"
        />


    <Button
        android:id="@+id/bt_test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:text="click me"
        android:focusableInTouchMode="true"
        />

</LinearLayout>

 我们分别为 LinearLayout , View , Button 都增加一个触摸时能够获取到焦点的属性。

package com.yuneec.testdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {



    private View view_test;
    private Button bt_test;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        view_test = findViewById(R.id.view_test);
        bt_test = (Button) findViewById(R.id.bt_test);

        view_test.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("xp.chen", "I am view, click................");
            }
        });

        view_test.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                Log.i("xp.chen", "==========================================");
                Log.i("xp.chen", "I am view, focus: "+view_test.isFocused());
                Log.i("xp.chen", "I am button, focus: "+bt_test.isFocused());
            }
        });

        bt_test.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("xp.chen", "I am button, click................");
            }
        });

        bt_test.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                Log.i("xp.chen", "==========================================");
                Log.i("xp.chen", "I am button, focus: "+bt_test.isFocused());
                Log.i("xp.chen", "I am view, focus: "+view_test.isFocused());
            }
        });
    }

}

我们先点击View, 发现View的onClick事件并未打印,再点击View,发现View的OnClick事件可以正常打印了;

然后再点击Button,发现Button的OnClick事件也未打印,再点击一次Button,发现Button的onClick事件可以正常打印了。

这说明第一次点击View或者Button,只是单纯的将焦点转换到了View或者Button上,此时会调用 OnFocusChangeListener 方法,只有当再次点击的时候才会调用onClick方法。

因此,这种操作对Button来说是多余的(我点击哪个Button,就意味着我想触发哪个Button的onClick事件, 不是说点击哪个Button,先去让这个Button获得焦点),而Button的 android:focusableInTouchMode 属性默认也就是false。

但对  EditText 这种控件来说就不一样了,比方说一个界面上有很多 EditText ,在用户点击了其中一个的时候,就代表用户想要在这个EditText里进行输入,那么这个EditText就必须立即获得焦点,弹出软键盘等待用户输入。事实上在Android源代码里面,EditText的 android:focusableInTouchMode  属性默认也就是 true 。参见AOSP中对EditText的属性定义:

<style name="Widget.EditText">
        <item name="android:focusable">true</item>
        <item name="android:focusableInTouchMode">true</item>
        <item name="android:clickable">true</item>
        <item name="android:background">?android:attr/editTextBackground</item>
        <item name="android:textAppearance">?android:attr/textAppearanceMediumInverse</item>
        <item name="android:textColor">?android:attr/editTextColor</item>
        <item name="android:gravity">center_vertical</item>
    </style>

可以尝试下将EditText的 android:focusableInTouchMode 属性设置为false,这样在手机上点击EditText,由于获取不到焦点,软键盘无法弹出。

参考链接:

Android中最详细的焦点问题,从概念出发带你一点点分享(1)

原文地址:https://www.cnblogs.com/yongdaimi/p/10607997.html