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,由于获取不到焦点,软键盘无法弹出。
参考链接: