Material Design 之 TextInputLayout和TextInputEditText

6,637 阅读6分钟

写在前面

更多Material Design 文章请看:
Material Design 之 Toolbar 开发实践总结
Material Design之 AppbarLayout 开发实践总结
Material Design 之 Behavior的使用和自定义Behavior
Material Design 之 TabLayout 使用
文本框相信大家都很熟悉,文本框可以让用户输入文本。它们可以是单行的,带或不带滚动条,也可以是多行的,并且带有一个图标。点击文本框后显示光标,并自动显示键盘。除了输入,文本框可以进行其他任务操作,如文本选择(剪切,复制,粘贴)以及数据的自动查找功能。这篇文章讲的就是Material Design 风格的文本框,它有有一些比较炫酷的动画效果(比如输入的时候,内嵌标签会浮动到内容的上方),此外还给我一些特别有用的功能,如错误提示、计数等等。Material Design 风格的文本框是用TextInputLayout 和TextInputEditText 两个View来实现的,该类support design 包中。下面就来看一下TextInputLayout 的具体用法。

TextInputLayout 使用

TextInputLayout介绍

首先来看一下TextInputLayout,TextInputLayout 是EditText(或者EditText子类)的一个包装类,它主要用于在用户输入文本的时候显示一个浮动标签,也支持显示错误信息和字符计数等功能。同样它也支持密码可见切换按钮,通过setPasswordVisibilityToggleEnabled(boolean)API 或者 xml 中的属性,如果设置该属性为可用(enable),那么当EditText 显示设置的密码时,会显示一个切换密码可见和隐藏的按钮。

注意:当使用密码切换按钮的时候,EditText 结束位置的 图标时会被覆盖的,为了保证EditText 结束位置Drawable的正常显示,你需要设置这些Drawables 的相对位置( 相对start的位置/相对结束的位置)。

图标覆盖,如下图:

override_drawable.png

如上图所示,切换密码可见的按钮(眼睛图标)和错误提示的图标 覆盖在一起了。

TextInputLayout 重要方法和属性

来看一下TextInputLayout 的一些重要方法和属性:

  • app:counterEnabled 字符计数是否可用
    代码中对应的方法为:setCounterEnabled(boolean)

  • app:counterMaxLength 计数最大的长度
    代码中对应的方法为:setCounterMaxLength(int )

  • app:counterOverflowTextAppearance 计数超过最大长度时显示的文本样式

  • app:counterTextAppearance 显示的计数的文本样式。

  • app:errorEnabled 显示错误信息是否可用

  • app:errorTextAppearance 显示错误信息的文本样式

  • android:hint 浮动标签
    代码对应方法:setHint(CharSequence)

  • app:hintAnimationEnabled 控制是否需要浮动标签的动画
    代码对应方法:setHintAnimationEnabled(boolean)
  • app:hintEnabled 控制是否显示浮动标签
    代码对应方法:setHintEnabled(boolean)
  • app:hintTextAppearance 浮动标签的文本样式
    代码对应方法:setHintTextAppearance(int)
  • app:passwordToggleDrawable 密码可见切换图标
    代码对应方法:setPasswordVisibilityToggleDrawable(int)或者setPasswordVisibilityToggleDrawable(Drawable)
  • app:passwordToggleEnabled 控制是否显示密码可见切换图标
    代码对应方法:setPasswordVisibilityToggleEnabled(boolean)
TextInputLayout 使用示例

了解了以上的属性和方法后,我们看一下具体使用:
1,带浮动标签的文本框
代码如下:

     />
    <android.support.design.widget.TextInputLayout
        android:id="@+id/text_input_layout_user"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        app:counterOverflowTextAppearance="@style/TextOverCount"
        android:scrollbarAlwaysDrawHorizontalTrack="true"
        android:textColorHint="@color/colorHint"
        >
         <EditText
             android:id="@+id/text_input_user"
             android:layout_width="match_parent"
             android:layout_height="48dp"
             android:hint="用户名"
             android:inputType="text"
             android:textColor="@color/black"
             />

    </android.support.design.widget.TextInputLayout>
    <android.support.design.widget.TextInputLayout
        android:id="@+id/text_input_layout_phone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        app:counterOverflowTextAppearance="@style/TextOverCount"
        android:scrollbarAlwaysDrawHorizontalTrack="true"
        android:textColorHint="@color/colorHint"
        >
        <EditText
            android:id="@+id/text_input_phone"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:hint="手机号码"
            android:inputType="number"
            android:textColor="@color/black"
            />

    </android.support.design.widget.TextInputLayout>

效果如下:

Floating_label.gif

2,带字符计数的文本框
布局:

<android.support.design.widget.TextInputLayout
        android:id="@+id/text_input_layout_user"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:textColorHint="@color/colorHint"
        >
         <EditText
             android:id="@+id/text_input_user"
             android:layout_width="match_parent"
             android:layout_height="48dp"
             android:hint="用户名"
             android:inputType="text"
             android:textColor="@color/black"
             />

    </android.support.design.widget.TextInputLayout>
    <android.support.design.widget.TextInputLayout
        android:id="@+id/text_input_layout_phone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"

        android:scrollbarAlwaysDrawHorizontalTrack="true"
        android:textColorHint="@color/colorHint"
        >
        <EditText
            android:id="@+id/text_input_phone"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:hint="手机号码"
            android:inputType="number"
            android:textColor="@color/black"
            />
    </android.support.design.widget.TextInputLayout>

在Activity 中设置,计数的长度:


        mTextInputLayoutUser = (TextInputLayout) findViewById(R.id.text_input_layout_user);
        //设置可以计数
        mTextInputLayoutUser.setCounterEnabled(true);
        //计数的最大值
        mTextInputLayoutUser.setCounterMaxLength(20);

效果如下:

count_edittext.gif

如上图所示,右下角会自动计数,当超过最大值时,计数文本、浮动标签和下标线都变成了红色,然后我们也可以用上面介绍的属性来更改:
添加代码

app:counterOverflowTextAppearance="@style/TextOverCount"

style 的代码如下:


    <style name="TextOverCount" parent="Base.TextAppearance.AppCompat.Light.Widget.PopupMenu.Small">
      <item name="android:textColor">@android:color/holo_green_light</item>
    </style>

效果如下:

count_over_apprence.png

如上图,将显示的颜色改为了绿色,当然也可以在style中改字体的大小,在添加一个item 就行

<item name="android:textSize">20sp</item>

更改计数文本的显示样式是一样的,定义一个style ,然后通过app:counterTextAppearance 设置就行。

3,显示密码可见和隐藏的切换按钮
代码如下:

 <android.support.design.widget.TextInputLayout
        android:id="@+id/text_input_layout_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:textColorHint="@color/colorHint"
        app:passwordToggleEnabled="true"
        app:passwordToggleTint="@color/colorHint"
        app:passwordToggleDrawable="@drawable/ic_eye_grey_24dp"
        >

        <android.support.design.widget.TextInputEditText
            android:id="@+id/text_input_password"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:hint="密码"
            android:textColor="@color/black"
            android:inputType="textPassword"
            android:singleLine="true"
            />
    </android.support.design.widget.TextInputLayout>

效果如下:

toggle.gif

如上图,可以看到,右边多了一个图标,点击图标可以使密码是明文或者隐藏。只是在布局文件中添加了几个属性

        app:passwordToggleEnabled="true"
        app:passwordToggleTint="@color/colorHint"
        app:passwordToggleDrawable="@drawable/ic_eye_grey_24dp"

当然了,也可依在代码中设置,一样的效果,不在演示。
4, 显示错误信息
TextInputLayout 是可以显示错误信息的,这种需求很常见没,比如登录的时候密码错误,给出相应的提示,比Toast 提示更加友好。
代码如下:

        mTextInputLayoutPassword = (TextInputLayout) findViewById(R.id.text_input_layout_password);
        mInputEditTextPassword = (TextInputEditText) findViewById(R.id.text_input_password);

        mInputEditTextPassword.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                mTextInputLayoutPassword.setErrorEnabled(false);
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String password = mInputEditTextPassword.getText().toString();
                if(TextUtils.isEmpty(password)||password.length()<6){
                    mTextInputLayoutPassword.setError("密码错误不能少于6个字符");
                }

            }
        });

效果如下:

error_tip.gif

当密码不正确的时候,显示错误提示,当内容发生变幻的时候,记得调用

mTextInputLayoutPassword.setErrorEnabled(false);

否则错误信息会一直显示界面上。

当然有些时候我们不需要浮动标签,或者不需要浮动标签的动画,我们可以控制,将对应属性设置为false就行了。

TextInputEditText 使用

上面讲了TextInputLayout的使用,那么TextInputEditText是干什么的呢? 其实就是一个EditText 的子类,上面讲的所有功能,TextInputLayout 里面包的子View既可以是EditText,也可以是TextInputEditText,效果是一样的。根据文档的解释,官网原文:A special sub-class of EditText
designed for use as a child of TextInputLayout。Using this class allows us to display a hint in the IME when in 'extract' mode.

解释:TextInputEditText 是 EditText 的子类,专门用作TextInputLayout的子View。它允许再`extract`模式(提取模式)下显示浮动标签。

也看过一些文章说,横屏模式EditText 不显示浮动标签,TextInputEditText 会显示浮动标签,但是我测试了一下,并没有发现所说的EditText 不显示浮动标签,TextInputEditText 会显示浮动标签。如果有知道的,请在评论区告知一下。,测试效果如下:(上看两个是EditText,最后一个是TextInputEditText)

text_input_edit.gif

TextInputEditText 、EditText 作为TextInputLayout 的子View使用差别很小,既然Google 说在extract 模式下TextInputEditText 更好,那我们开发中使用TextInputEditText配合TextInputLayout使用就好了。

另外,上面讲了TextInputLayout 可以显示错误信息,TextInputEditText也是可以显示错误信息的,用下面两个方法:

mInputEditTextUser.setError("格式不正确");
//或者
mInputEditTextUser.setError("格式不正确",getDrawable(R.drawable.activity_close));

error_tip2.png

最后

以上就是TextInputLayout和TextInputEditText 的全部内容,Demo 请戳MaterialDesignSamples。元旦之前来一发,祝大家元旦快乐!!