EditText软键盘的显示隐藏及焦点问题

简介

EditText作为Android输入框,对于Android开发来说,是不能再熟悉的一个控件。但是,使用EditText 有很多的细节需要注意。比如它的一些常用属性、焦点问题、软键盘的显示隐藏等。在此,我做一些笔记,方便自己使用和记忆。

EditText 基本知识

示例代码:

<EditText
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:gravity="center_vertical"
    android:paddingLeft="12dp"
    android:paddingRight="12dp"
    android:background="#ffffff"
    android:hint="请输入"
    android:textSize="14px"
    android:inputType="text"
    android:maxLines="1"
    android:maxLength="20"
    android:textColor="#333333"
    android:textColorHint="#999999"
    />

常用属性及作用

  • hint 和 tools:text

hint 属性主要用于设置提示文字,颜色可以通过属性 textColorHint 设置,如:android:textColorHint="#999999" 即设置提示文字颜色为#999999(浅灰色)。

tools:text 属性用于开发时显示文字,需要命名空间
xmlns:tools="http://schemas.android.com/tools"
与android:text 不同,它只在开发工具的预览(Preview)中可见,用于辅助开发。

类似的还有
tools:visibility="visible" 当我们设置android:visibility="gone"后,再加上这句代码,就可以在预览中显示,实际中不显示,以方便开发。tools 当然还有很多其他属性,可以自己去发现。

  • maxLines、minLines、lines、maxLength、ems

maxLines:最大显示行数,当EditText设置高度为wrap_content,即android:layout_height="wrap_content"后,设置最大显示行数,可以起到约束高度的效果。即高度随内容的行数增加,直到行数为maxLines高度不再增加。

minLines:最小显示行数。当内容行数小于minLines时,EditText高度为minLines行高度,大于minLines行时,高度自适应。

lines:显示行数,用于约束EditText行数,当EditText设置高度为wrap_content,EditText会显示行数为 lines时的高度,不管内容有多少。

maxLength:最大长度,限制内容长度,最大为maxLength。比较常用。

ems:当前字体下,最多可编辑多少个M字母宽度。设置为10时,最多编辑 10个em ,一个em单位是 两个inch ,但是随着自动调整,在Android中 em代表‘M’的数量 。可以设置属性maxEmsminEms

  • inputType

输入类型,EditText接受的输入类型,可以控制软键盘的输入类型。

    android:inputType="none"//输入普通字符
    android:inputType="text"//输入普通字符
    android:inputType="textCapCharacters"//输入普通字符
    android:inputType="textCapWords"//单词首字母大小
    android:inputType="textCapSentences"//仅第一个字母大小
    android:inputType="textAutoCorrect"//前两个自动完成
    android:inputType="textAutoComplete"//前两个自动完成
    android:inputType="textMultiLine"//多行输入
    android:inputType="textImeMultiLine"//输入法多行(不一定支持)
    android:inputType="textNoSuggestions"//不提示
    android:inputType="textUri"//URI格式
    android:inputType="textEmailAddress"//电子邮件地址格式
    android:inputType="textEmailSubject"//邮件主题格式
    android:inputType="textShortMessage"//短消息格式
    android:inputType="textLongMessage"//长消息格式
    android:inputType="textPersonName"//人名格式
    android:inputType="textPostalAddress"//邮政格式
    android:inputType="textPassword"//密码格式
    android:inputType="textVisiblePassword"//密码可见格式
    android:inputType="textWebEditText"//作为网页表单的文本格式
    android:inputType="textFilter"//文本筛选格式
    android:inputType="textPhonetic"//拼音输入格式
 
 
    //数值类型
    android:inputType="number"//数字格式
    android:inputType="numberSigned"//有符号数字格式
    android:inputType="numberDecimal"//可以带小数点的浮点格式
    android:inputType="phone"//拨号键盘
    android:inputType="datetime"//日期+时间格式
    android:inputType="date"//日期键盘
    android:inputType="time"//时间键盘

参考:https://blog.csdn.net/zhangphil/article/details/79970667

  • imeOptions

根据输入框输入完成后要执行的业务逻辑指定软键盘右下角Action按钮的样式和行为,如让右下角按钮显示为“搜索”,点击后执行搜索逻辑。

imeOptions 有下面一些值:

imeOptions 属性值 对应字段(EditorInfo.) 描述
actionDone IME_ACTION_DONE 完成
actionGo IME_ACTION_GO 前进
actionNext IME_ACTION_NEXT 下一项
actionPrevious IME_ACTION_PREVIOUS 上一项
actionSearch IME_ACTION_SEARCH 搜索
actionNone IME_ACTION_NONE 无动作
actionUnspecified IME_ACTION_UNSPECIFIED 未指定
actionSend IME_ACTION_SEND 发送
flagForceAscii IME_FLAG_FORCE_ASCII 请求IME输入法接受ASCII字符的输入。
flagNoFullscreen IME_FLAG_NO_FULLSCREEN 请求IME输入法永远不要进入全屏模式。
flagNavigateNext IME_FLAG_NAVIGATE_NEXT 表明这里有前进导航可以关注的兴趣点,类似`IME_ACTION_NEXT`,不过允许IME输入多行且提供前进导航。
flagNavigatePrevious IME_FLAG_NAVIGATE_PREVIOUS 类似IME_FLAG_NAVIGATE_NEXT, 表明这里有后退导航可以关注的兴趣点。
flagNoAccessoryAction IME_FLAG_NO_ACCESSORY_ACTION 和一个Action结合使用表明在全屏输入法中不作为可访问性按钮。
flagNoEnterAction IME_FLAG_NO_ENTER_ACTION 多行文本将自动设置了该标志位,执行Action时为换行效果,如果未设置,IME输入法将把Enter按钮自动替换为Action按钮。
flagNoExtractUi IME_FLAG_NO_EXTRACT_UI 请求IME输入法不要显示额外的文本UI。

java代码:

mEt.setImeOptions(EditorInfo.actionDone);//完成

监听:

mEt.setOnEditorActionListener(new OnEditorActionListener() {  
            @Override  
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {  
               if (actionId == EditorInfo.IME_ACTION_DONE) {
               // 按下完成按钮,这里和上面imeOptions对应
                text.setText("Editing EditorInfo.IME_ACTION_DONE");  
                return false;   //返回true,保留软键盘。false,隐藏软键盘
                }
            }  
        });  

参考:https://blog.csdn.net/honjane/article/details/78699002

  • cursorVisible 和 textCursorDrawable

cursorVisible:光标是否可见。
textCursorDrawable:设置光标的样式。
通过shape可以设置光标样式:


<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <size android:width="2dp" />
    <solid android:color="#1b9fff"  />
shape>

加上padding可以处理末尾光标显示不全问题:


<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <size android:width="1.2dp" />
    <solid android:color="#1b9fff" />
    <padding android:left="1.2dp" android:right="1.2dp" />
shape>
  • selectAllOnFocus

android:selectAllOnFocus="true":当得到焦点时选择全部。

软件盘的窗口输入模式和显示隐藏

  • 窗口输入模式

在清单文件中,可通过设置属性android:windowSoftInputMode (窗口输入模式),控制软键盘的可见性和软键盘显示时窗口的调整。例如:

<activity
    android:name=".AaActivity"
    android:windowSoftInputMode="stateVisible|adjustPan"
    android:screenOrientation="portrait" />

上面是 AndroidManifest.xml 文件中的设置,代码设置需要使用Activity的方法getWindow().setSoftInputMode(int),如下:

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);

下面是窗口软键盘输入模式的属性值及其描述:

windowSoftInputMode 属性值 对应字段(WindowManager.LayoutParams.) 描述
stateUnspecified SOFT_INPUT_STATE_UNSPECIFIED 可见性状态:未指定。系统将选择一个合适的状态或依赖于主题的设置。
stateUnchanged SOFT_INPUT_STATE_UNCHANGED 可见性状态:不更改输入区(软键盘)的状态。当这个activity出现时,软键盘将一直保持在上一个activity里的状态,无论是隐藏还是显示。
stateVisible SOFT_INPUT_STATE_VISIBLE 可见性状态:当定位到你的窗口时,显示软键盘。(如:进入AaActivity时,显示软键盘)
stateAlwaysVisible SOFT_INPUT_STATE_ALWAYS_VISIBLE 可见性状态:当前窗口获取输入焦点时,始终显示软键盘。
stateHidden SOFT_INPUT_STATE_HIDDEN 可见性状态:当定位到你的窗口时,隐藏软键盘。(如:进入AaActivity时,隐藏软键盘)
stateAlwaysHidden SOFT_INPUT_STATE_ALWAYS_HIDDEN 可见性状态:当前窗口获取焦点时,始终隐藏软键盘。
adjustUnspecified SOFT_INPUT_ADJUST_UNSPECIFIED 调整选项:未指定。系统会根据窗口内容尝试选择adjustResize和adjustPan其中一个调整选项。
adjustResize SOFT_INPUT_ADJUST_RESIZE 调整选项:设置为允许在显示输入法时调整窗口的大小,以便输入方法不覆盖其内容,即窗口大小调整。不能和SOFT_INPUT_ADJUST_PAN连用。这两个都没有设置,系统将根据窗口内容选择其中一个。如果窗口的布局参数标志(layout parameter flags)包含FLAG_FULLSCREEN,这个将失效,窗口不会调整大小,但会保持全屏。
adjustPan SOFT_INPUT_ADJUST_PAN 调整选项:当显示输入方法时,设置为可以窗口平移,因此不需要调整大小处理,但只需通过框架平移以确保当前输入焦点可见,即窗口平移调整。当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分。不能和SOFT_INPUT_ADJUST_PAN连用。
adjustNothing SOFT_INPUT_ADJUST_NOTHING 调整选项:不因输入法的显示调整窗口,不会调整窗口大小,也不会被平移以使其焦点可见。
  • 输入法显示隐藏工具类

软件盘的显示隐藏,这里提供一个工具类:

/**
 * 软键盘工具类
 *   ·是否隐藏
 *   ·显示
 *   ·隐藏
 */
public class SoftInputUtil {

    /**
     *  判断键盘是否显示(当前editText是否在输入法活动状态,即是否正在接收软键盘输入)。
     * @param editText 输入框
     */
    public static boolean isSoftInputShowing(EditText editText){
        return isSoftInputShowing(editText.getContext(), editText);

    }

    /**
     * 判断键盘是否显示(当前view是否在输入法活动状态,即是否正在接收软键盘输入)。
     * @param context 上下文
     * @param view 当前聚焦的正在接收软件盘输入的View。
     */
    public static boolean isSoftInputShowing(Context context, View view) {
        boolean bool = false;
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null && imm.isActive(view)) {
            bool = true;
        }
        return bool;
    }

    /**
     * 判断键盘是否显示(是否有View是在输入法活动状态,即是否正有View正在接收软键盘输入)。
     * @param context 上下文
     */
    public static boolean isSoftInputShowing(Context context) {
        boolean bool = false;
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null && imm.isActive()) {
            bool = true;
        }
        return bool;
    }

    /**
     * 显示键盘
     * @param view 当前聚焦的正在接收软件盘输入的View,通常为EditText。
     */
    public static void showSoftInput(View view) {
        showSoftInput(view.getContext(), view);
    }

    /**
     * 显示键盘
     * @param context 上下文
     * @param view 当前聚焦的正在接收软件盘输入的View,通常为EditText。
     */
    public static void showSoftInput(Context context, View view) {
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null) {
            //第二个参数为flags, 0 | InputMethodManager.SHOW_FORCED | InputMethodManager.SHOW_IMPLICIT
            imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
        }
    }

    /**
     * 隐藏软键盘
     * @param activity
     */
    public static void hideSoftInput(Activity activity) {
        View view = activity.getWindow().peekDecorView();
        if (view != null) {
            hideSoftInput(activity, view);
        }
    }

    public static void hideSoftInput(View view) {
        if (view != null) {
            hideSoftInput(view.getContext(), view);
        }
    }

    /**
     * 隐藏输入法
     * @param context 上下文
     * @param view 可以是任意已添加到window中的View(已添加到布局中的View)。
     */
    public static void hideSoftInput(Context context, View view) {
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null && imm.isActive()) {
            //第二个参数为flags, 0 | InputMethodManager.HIDE_IMPLICIT_ONLY | InputMethodManager.HIDE_NOT_ALWAYS
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
    }
    
}

EditText 焦点问题

有时候我们想要一进入界面(带有输入框)就显示或隐藏输入法(软键盘)。除了通过设置上面介绍的窗口输入模式,也可以通过EditText 获取和失去焦点来影响软键盘的显示或隐藏。

如果没有设置窗口的输入模式,系统会根据窗口内容自动选择一个合适的模式。

· 一进界面显示输入法

想要一进界面就把叫焦点和光标定位到某个输入框,并显示输入法,可以设置属性 focusablefocusableInTouchModetrue,如下所示:

<EditText
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:gravity="center_vertical"
    android:paddingLeft="12dp"
    android:paddingRight="12dp"
    android:background="#ffffff"
    android:hint="请输入"
    android:textSize="14px"
    android:inputType="text"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:textColor="#333333"
    android:textColorHint="#999999"
    />

· 一进界面隐藏输入法

进入界面时不想让输入框获得焦点,不显示光标,不显示输入框,可以去掉上面的 EditText 的 focusable 和 focusableInTouchMode 属性,给它的父容器或最外层容器或其他不相干的View设置这两个属性为true,把焦点转移出去。否则,系统会检测焦点,当找不到其他可获得焦点的View时,会检测到输入框把焦点交给它;当有多个输入框的时候,焦点可能转移到其他输入框。

如果想在触发点击事件时隐藏软件盘并且使光标不可见,可使用如下代码:

    public void hideSoftInput(View root) {
        View v = root.findFocus();
        if (v != null && (v instanceof EditText)) {
            //使EditText触发一次失去焦点事件
            v.setFocusable(false);
//                v.setFocusable(true); //这里不需要是因为下面一句代码会同时实现这个功能
            v.setFocusableInTouchMode(true);

        }
        SoftInputUtil.hideSoftInput(v);
    }

在点击监听回调等合适的地方隐藏软键盘。
注意:SoftInputUtil 是上面提供的工具类。参数root最好是当前页所有输入框共同的父容器。

在Activity中可以使用方法 getCurrentFocus(),获取到当前得到焦点的View,上面代码就可以是:

    public void hideSoftInput() {
        View v = getCurrentFocus();
        if (v != null && (v instanceof EditText)) {
            //使EditText触发一次失去焦点事件
            v.setFocusable(false);
//                v.setFocusable(true); //这里不需要是因为下面一句代码会同时实现这个功能
            v.setFocusableInTouchMode(true);

        }
        SoftInputUtil.hideSoftInput(v);
    }

如果想在输入框外部点击都隐藏输入框,可以参考 Android中EditText焦点问题:https://www.jianshu.com/p/3d31d681f4bc

参考:
[1] https://blog.csdn.net/a641324093/article/details/62238385
[2] https://blog.csdn.net/honjane/article/details/78699002
[3] https://www.jianshu.com/p/4e238eb1deb2
[4] https://blog.csdn.net/wei_zhi/article/details/50183605?utm_source=itdadao&utm_medium=referral
[5] Android中EditText焦点问题:https://www.jianshu.com/p/3d31d681f4bc

你可能感兴趣的:(android)