Android 控件学习之 TextInputLayout

之前在做一个登录界面的简单 Demo 时,发现官方模板文件中提供的界面控件有几个不太属性的面孔,趁机学习一番,本文记录的就是其中的 TextInputLayout。

基本功能

根据官方文档 TextInputLayout 控件的最大作用是,包裹 EditText 控件以及它的派生控件,并未这些文字输入控件提供可浮动的提示文字。具体效果如下所示:

example.gif
这样的好处非常明显,相比单一的 EditText 这样可以把提示信息很好的保存下来,极大地方便了用户。

TextInputLayout 也提供了更清晰的错误信息显示模式:

error.gif
相比原来 EditText 默认在输入框右侧的错误图标提示,这样的错误提示方式更加清晰直白。

高级功能

TextInputLayout 还提供了输入字符计数功能:

count.gif
通过在 layout 文件的加入 xml 标签属性 app:counterMaxLength,同设置这个属性的数值来调整计数最大值。

不使用 TextInputLayout 要实现密码可见性转换功能必须使用自定义的 EditText 子类控件,编写复杂的代码。但是,TextInputLayout 把功能很好的集成到了 xml 标签的属性中,分别是:

  • app:setPasswordVisibilityToggleEnabled:开启可见性转换功能
  • app:passwordToggleDrawable:功能点击图标的图像资源文件
  • app:passwordToggleContentDescription:功能描述,方便辅助设备播报功能的语音或显示文字提示
  • app:setPasswordVisibilityToggleTintList:传入 tint 列表,调整图像颜色
  • app:setPasswordVisibilityToggleTintMode:设置 tint 模式

xml 属性也有对应的类的方法,方法名称和属性名称完全相同。

需要注意的是,最初的可见性转换功能是自动开启的,但是之后官方意识到可能会和一些用户自定义的可见性转换控件发生冲突,所以之后默认关闭了它。如果要使用这个功能,必须手动将 app:setPasswordVisibilityToggleEnabled 设为 true 才行。 在 layout 文件中设置好 xml 属性,无需任何 java 代码就能简单实现密码可见性转换功能。

这里要注意,如果指示简单的设置一个 icon 图片的话,转换密码可见性的图标是不会随着点击而改变的。这样的密码框虽然也能使用,但是显然很不友好。 实际改进的办法也比较简单就是使用 selector 标签定义一个 StateListDrawable,让 icon 随着点击而改变图像。那么 selectoritem 的状态到底怎么设置呢? 实际的设置方法要参考源代码中密码可见性的详细实现:

1
2
3
4
5
6
public void setPasswordVisibilityToggleDrawable(@Nullable Drawable icon) {
    mPasswordToggleDrawable = icon;
    if (mPasswordToggleView != null) {
        mPasswordToggleView.setImageDrawable(icon);
    }
}

可以看到这个方法传入了图标的图片对象,并且使用 mPasswordToggleDrawable 保存,而放置图片的 View 则是 mPasswordToggleView 定义的,只要找到 mPasswordToggleView 的实现代码就能够确定 item 状态如何设置。 在域生命语句中发现如下内容:

1
private CheckableImageButton mPasswordToggleView;

mPasswordToggleView 类型为 CheckableImageButton,而后再查看 CheckableImageButton 的源码,找到如下内容:

1
private static final int[] DRAWABLE_STATE_CHECKED = new int[]{android.R.attr.state_checked};

终于明白图片 item 标签需要设定的属性为 android:state_checked

当然,熟悉 CheckableImageButton 的使用和内容应该一看到它就明白该如何定义属性了。

最后的代码为: 定义显示密码图标: {% codeblock lang:java src/main/res/drawable/ic_visibility.xml %}

{% endcodeblock %}

定义遮盖密码图标: {% codeblock lang:java src/main/res/drawable/ic_visibility_off.xml %}

{% endcodeblock %}

定义 StateListDrawable 内容: {% codeblock lang:java src/main/res/drawable/ic_visibility_toggle.xml %}

{% endcodeblock %}

layout 示例代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<-- 省略无关代码 -->

  <android.support.design.widget.TextInputLayout
      android:id="@+id/password_container"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:passwordToggleContentDescription="@string/toggle_password"
      app:passwordToggleDrawable="@drawable/ic_visibility_toggle"
      app:passwordToggleEnabled="true"
      >
    <android.support.design.widget.TextInputEditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textPassword"
        />
  </android.support.design.widget.TextInputLayout>

<-- 省略无关代码 -->

最后得到效果如下:

visibility.gif