Android中涉及到的焦点问题,focusable,clickable,enabled

先摘抄下stackoverflow上一个启发了我的回答:

try by Changing your code as:


private OnClickListener saveButtonListener = new OnClickListener() {


    @Override
    public void onClick(View v) {
                Text1.clearFocus();
                Text2.clearFocus();
                saveButton.requestFocus(); //or any other View
    }


}
because as doc as about public void clearFocus () :


Called when this view wants to give up focus. If focus is cleared onFocusChanged(boolean, int, android.graphics.Rect) is called.


Note: When a View clears focus the framework is trying to give focus to the first focusable View from the top. Hence, if this View is the first from the top that can take focus, then all callbacks related to clearing focus will be invoked after wich the framework will give focus to this view.
means you must set Focus to other view on button click because Text1 act as first View in your layout


意思就是说,当EditText的clearfocus清除焦点的时候,框架更倾向于把焦点给试图层上的第一个能够获取焦点的view

其实View的属性里有一下配置分别对应不同的事件

android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="true"
android:enabled="true"

android:state_enabled="false"
android:state_pressed="true"
android:state_focused="true"

很熟悉这些东西,比较常用到的地方是在drawable文件下配置一个背景的selector.xml的时候有配置当获得焦点时显示什么背景,按下去什么背景,enabled为false什么背景。

但是开发项目中,我遇到的场景是:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.widget.TitleBar
        android:id="@+id/title_bar"
        android:layout_width="match_parent"
        android:layout_gravity="top"
        android:layout_height="49dp" >

        <TextView
            android:id="@+id/titlebar_save"
            android:layout_width="60dp"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
<span style="white-space:pre">	</span>    android:focusable="true"
        android:focusableInTouchMode="true"
            android:background="@drawable/titlebar_btn_bg_selector"
            android:gravity="center"
            android:text="保存"
            android:textColor="@color/common_white"
            android:textSize="17sp" />
    </com.widget.TitleBar>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="49dp"
        android:scrollbars="none" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <RelativeLayout
                android:id="@+id/account_head_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingBottom="25dp"
                android:paddingLeft="12dp"
                android:paddingRight="12dp"
                android:paddingTop="25dp" >

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:text="头像"
                    android:textColor="@color/black_333333"
                    android:textSize="16sp" />
                
                <ImageView
                    android:id="@+id/ico_set_arrow"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentRight="true"
                    android:background="@color/transparent"
                    android:src="@drawable/ico_set_arrow"
                    android:layout_centerVertical="true"
                    android:layout_marginLeft="12dp"/>
                <com.widget.RoundedImageView
                    android:id="@+id/account_head"
                    android:layout_width="76dp"
                    android:layout_height="76dp"
                    android:layout_centerVertical="true"
                    android:layout_toLeftOf="@id/ico_set_arrow"
                    android:scaleType="centerCrop"
			        android:src="@drawable/default_head" />
            </RelativeLayout>


                <include
	                style="@style/setting_dividing_line_style"
	                android:layout_width="match_parent"
	                android:layout_height="1.5dp"
	                android:layout_marginLeft="12dp"
	                android:layout_marginRight="12dp"
	                android:layout_marginTop="10dp"
	                layout="@layout/widget_horizontal_dividing_line" />
                
                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:paddingLeft="12dp"
                    android:paddingRight="20dp" >

                    <TextView
                        style="@style/setting_item_text_style"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentLeft="true"
                        android:layout_centerVertical="true"
                        android:text="昵称" />
                    
                    <LinearLayout android:layout_width="0dp"
			            android:layout_height="0dp"
			            android:focusable="true"
			            android:focusableInTouchMode="true">
			            <requestFocus />
			        </LinearLayout>

                    <com.widget.CustomInputBox
                        android:id="@+id/account_nickname"
                        android:layout_width="120dp"
                        android:layout_height="match_parent"
                        android:singleLine="true"
                        android:paddingTop="5dp"
                        android:gravity="center_vertical"
                        android:layout_alignParentRight="true"
                        android:layout_centerVertical="true"
                        android:background="@color/transparent" />
                </RelativeLayout>

                <include
                    style="@style/setting_dividing_line_style"
                    android:layout_width="match_parent"
                    android:layout_height="0.5dp"
                    android:layout_marginLeft="12dp"
                    android:layout_marginRight="12dp"
                    layout="@layout/widget_horizontal_dividing_line" />

                <RelativeLayout
                    android:id="@+id/account_sex_layout"
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:paddingLeft="12dp"
                    android:paddingRight="20dp" >

                    <TextView
                        style="@style/setting_item_text_style"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentLeft="true"
                        android:layout_centerVertical="true"
                        android:text="性别" />

                    <TextView
                        android:id="@+id/account_sex"
                        style="@style/account_item_text_style"
                        android:layout_width="80dp"
                        android:layout_height="match_parent"
                        android:gravity="center_vertical|right"
                        android:layout_alignParentRight="true"
                        android:layout_centerVertical="true"
                        android:text="保密" />
                </RelativeLayout>
                
                <include
                    style="@style/setting_dividing_line_style"
                    android:layout_width="match_parent"
                    android:layout_height="0.5dp"
                    android:layout_marginLeft="12dp"
                    android:layout_marginRight="12dp"
                    layout="@layout/widget_horizontal_dividing_line" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="40dp"
                android:orientation="vertical"
                android:paddingRight="0dp"
                android:paddingBottom="20dp" >

                <TextView
                    style="@style/setting_item_text_style"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="12dp"
                    android:text="个性签名" />

                <include
                    style="@style/setting_dividing_line_style"
                    android:layout_width="match_parent"
                    android:layout_height="0.5dp"
                    android:layout_marginLeft="12dp"
                    android:layout_marginRight="0dp"
                    android:layout_marginTop="10dp"
                    layout="@layout/widget_horizontal_dividing_line" />

                <EditText
                    android:id="@+id/account_description"
                    style="@style/account_item_text_style"
                    android:hint="用一段话介绍自己..."
                    android:gravity="top"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="20dp"
                    android:layout_marginRight="20dp"
                    android:layout_marginTop="10dp"
                    android:paddingBottom="10dp"
                    android:background="@color/transparent"
                    android:ellipsize="end"
                    android:maxLines="3"
                    android:minLines="3" />
            </LinearLayout>
        </LinearLayout>
    </ScrollView>

</FrameLayout>

上面是我的layout,就一个比较简单的用户编辑,头部保存的textview设置了android:focusable="true"
            android:focusableInTouchMode="true"这两个属性,导致当按edittext获取焦点弹出软键盘后,编辑按保存的时候没有调用这个textview的setonclicklistener里面的onclick方法。

一直想不明白为什么,然后看到“当EditText的clearfocus清除焦点的时候,框架更倾向于把焦点给试图层上的第一个能够获取焦点的view”这句话,其实是那些能够获取焦点的view。

这里的头部保存的textview其实不是在top上的,个人觉得不是。因为当我把头部的focus两个属性设为false后是可以点击到的。(PS:默认的android:focusable="false" android:focusableInTouchMode="false"这两个属性是为false)。

这里我的推断是:当你为view配置了focusable属性后,同时也setOnclickListener了,如果其他的EditText获取焦点后,然后你点击能够focusable的view的时候发现这个view的onClick方法无法得到回调。也就是说focus和setOnClick其实是两个互相矛盾的操作,android系统默认如果这个view已经focus获得焦点了,就不应该执行onClick。


看系统源码也能多少猜测到

static class ListenerInfo {
        /**
         * Listener used to dispatch focus change events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        protected OnFocusChangeListener mOnFocusChangeListener;

        /**
         * Listeners for layout change events.
         */
        private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;

        /**
         * Listeners for attach events.
         */
        private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;

        /**
         * Listener used to dispatch click events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        public OnClickListener mOnClickListener;

        /**
         * Listener used to dispatch long click events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        protected OnLongClickListener mOnLongClickListener;

        /**
         * Listener used to build the context menu.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        protected OnCreateContextMenuListener mOnCreateContextMenuListener;

        private OnKeyListener mOnKeyListener;

        private OnTouchListener mOnTouchListener;

        private OnHoverListener mOnHoverListener;

        private OnGenericMotionListener mOnGenericMotionListener;

        private OnDragListener mOnDragListener;

        private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;

        OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
    }

这个是class  View里面的一个内部类,观察发现有clicklistener,focuschangelistener等,所以其实不要把focus和click混为一滩。


PS:如果有不同观点,欢迎留言交流









`android:clickable="true"` 和 `android:focusable="true"` 是 Android 开发中用于设置视图组件交互属性的两个 XML 属性。 ### 1. `android:clickable="true"` 当将这个属性设为 `"true"` 时,表示该视图是可以点击的。这意味着用户可以对该视图进行触摸操作,并触发相应的事件处理程序(如 `onClick`)。默认情况下,某些控件(例如按钮、图像按钮等)已经设置了此属性为 `true`,但对于一些基础视图(如 `View`, `TextView` 等),如果你希望它们能够响应点击事件,则需要显式地将其设置为 `true`。 ```xml <View android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" android:onClick="handleClick"/> ``` ### 2. `android:focusable="true"` 当将这个属性设为 `"true"` 时,意味着该视图可以在获取焦点的情况下被选中或高亮显示。这对于支持键盘导航的应用非常重要,因为只有那些允许聚焦的元素才能通过方向键或其他输入设备选择到并激活其功能。同时,在某些特定场景下(比如列表项之间的切换),也需要确保适当的 UI 组件能获得焦点以便提供更好的用户体验。 ```xml <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Focusable TextView" android:focusable="true"/> ``` 通常来说,如果一个视图既需要接收点击事件又想要参与到键盘导航体系当中去的话,一般会同时开启这两个选项: ```xml <Button android:id="@+id/myButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Clickable and Focusable Button" android:clickable="true" android:focusable="true" /> ``` 不过值得注意的是,默认情况下像 `Button` 这样的常用控件通常是自带了上述特性的,所以在实际项目里直接利用现有的控件即可满足大部分需求;而对于自定义 View 或者非标准交互模式下的界面设计则需特别注意是否合理配置了这两项重要特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值