MaterialDesign——TextInputLayout

目前代码已经上传到GitHub,里面有博客里面Material Design系列的所有代码
GitHub Material Design

1、什么是TextInputLayout?

TextInputLayout是22.2.0新添加的控件, 要和EditText(或EditText的子类)结合使用,并且只能包含一个EditText(或EditText的子类),这一点尤其重要,在做用户注册的时候遇到了TextInputLayout里面有获取验证码的按钮,布局的时候出现问题了,具体的解决方法详见下文,TextInputLayout的继承关系如下图所示。


image.png

2、为什么要用TextInputLayout?

遵循Material Design的设计,很多APP在用户登录、注册的页面中都使用了TextInputLayout的控件,在一些iOS的APP中也能发现这种想过,通过一些细微的动画效果以及改变颜色,能达到很炫酷的效果,相比传统的EditText,在用户输入信息的时,hint(提示)会自动上移,并且输入框的下划线会高亮,并能够把输入校验的错误能够在控件下面展示,不用Toast弹出提示,并且自带设置密码框的显示与隐藏,效果如下图所示。


TextinputLogin.gif

3、如何使用TextInputLayout?

3.1 首先在build.gradle 引入design的库

 implementation 'com.android.support:appcompat-v7:26.1.0'
 implementation 'com.android.support:design:26.1.0'

3.2 其次在xml文件中添加一下代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white">

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

        <include layout="@layout/custom_toolbar"/>


        <android.support.design.widget.TextInputLayout
            android:id="@+id/text_input_layout_phone"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="15dp"
            android:paddingRight="15dp"
            android:scrollbarAlwaysDrawHorizontalTrack="true"
            android:textColorHint="@color/colorHint"
            app:counterOverflowTextAppearance="@style/TextOverCount"
            app:errorTextAppearance="@style/text_input_login_error_style">

            <android.support.design.widget.TextInputEditText
                android:id="@+id/et_phone"
                style="@style/et_login_text"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:layout_centerVertical="true"
                android:hint="@string/phone_hint"
                android:inputType="number"
                android:maxLength="11"
                android:textColor="@color/black"
                android:textColorHint="@color/font_dark_color"
                android:textSize="@dimen/font_middle_size" />

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


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

            <android.support.design.widget.TextInputEditText
                android:id="@+id/et_pwd"
                style="@style/et_login_text"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="@string/pwd_hint"
                android:inputType="textPassword"
                android:maxLength="16"
                android:singleLine="true"
                android:textColor="@color/black"
                android:textSize="@dimen/font_middle_size" />
        </android.support.design.widget.TextInputLayout>


        <Button
            android:id="@+id/btn_login"
            android:layout_width="match_parent"
            android:layout_height="38dp"
            android:layout_marginLeft="80dp"
            android:layout_marginRight="80dp"
            android:layout_marginTop="60dp"
            android:layout_weight="1"
            android:background="@drawable/btn_login_bg_gradient"
            android:text="登录"
            android:textColor="@color/white"
            android:textSize="@dimen/font_small_size" />


    </LinearLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="18dp">

        <View
            android:id="@+id/view_center"
            android:layout_width="0.5dp"
            android:layout_height="16dp"
            android:layout_centerInParent="true"
            android:background="@color/line_default_color" />

        <TextView
            android:id="@+id/tv_modify_pwd"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="8dp"
            android:layout_toLeftOf="@id/view_center"
            android:text="忘记密码?"
            android:textColor="#ff5c5f5f"
            android:textSize="12dp" />

        <TextView
            android:id="@+id/tv_phone_register"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:layout_toRightOf="@id/view_center"
            android:text="注册"
            android:textColor="#ff5c5f5f"
            android:textSize="12dp" />
    </RelativeLayout>

</RelativeLayout>

3.3在activity中的设置

package com.codingsnail.materialdesigndemo.view

import CommonUtils
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.text.Editable
import android.text.TextWatcher
import android.widget.Toast
import com.codingsnail.materialdesigndemo.R
import kotlinx.android.synthetic.main.activity_text_input_login.*
import org.jetbrains.anko.sdk25.coroutines.onClick

/**
 * Created by Snail on 3/1/2018 11:31 AM
 * Contact with slowsnail0223@gmail.com
 */
class TextInputLoginActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_text_input_login)
        initView()
    }

    private fun initView() {

         et_phone.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                text_input_layout_phone.isErrorEnabled = false
            }

            override fun afterTextChanged(s: Editable) {

            }
        })
        et_pwd.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {

            }

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                text_input_layout_pwd.isErrorEnabled = false
            }

            override fun afterTextChanged(s: Editable) {
            }
        })

        btn_login.onClick {
            invalidLogin()
        }
    }


    private fun invalidLogin() {


        if (!CommonUtils.verifyMobile(et_phone!!.text.toString().trim())) {
            text_input_layout_phone.error = getString(R.string.error_field_phone)
            return
        }
        if (!CommonUtils.verifyLoginPwd(et_pwd!!.text.toString().trim())) {
            text_input_layout_pwd.error = getString(R.string.error_incorrect_password)
            return
        }
        Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show()
    }

    companion object {

        fun startActivity(context: Context) {
            context.startActivity(Intent(context, TextInputLoginActivity::class.java))
        }
    }
}

这样就能完成如上git图所看到的所有功能啦!

4、TextInputLayout的重要属性讲解

4.1 达到上面效果我们需要做到的步骤

image.png

XML中配置的如上图所示,这样就可以基本完成TextInputLayout的功能了,但是想使用TextInputLayout自带的错误提示功能,在代码中还需要设置以下两点。

4.1.1 需要给TextInputEditText添加 addTextChangedListener监听,当文本有变化的时候需要动态的去设置,整个项目都是用Kotlin写的,Java的写法也是一样,只是语法不一样。

text_input_layout_pwd.isErrorEnabled = false
image.png

4.1.2 校验错误的时候去设置错误提示

image.png

可以看到完成1、2点以后就可以使用TextInputLayout的错误提示功能了

4.2 如何改变默认的颜色,能够适配自己APP颜色风格的UI

image.png

如果我们不进行颜色设置的话,那么我们字体的颜色以及下划线的颜色一定和colorPrimary、colorPrimaryDark、colorAccent颜色是一样的。

     <!-- 代表 hint 的颜色 -->
        <item name="android:textColorHint">#ff6f7272</item>
        <!-- 代表 下划线没有获取焦点的颜色 的颜色 -->
        <item name="colorControlNormal">#ffd8d8d8</item>
        <!-- 代表 代表了获取焦点的时候 下划线 的颜色 -->
        <item name="colorControlActivated">#ff3586fe</item>
       <!-- 代表 代表了点击的时候 下划线 的颜色 -->
        <item name="colorControlHighlight">#ff3586fe</item>

然后在我们的AndroidManifest.xml 里面的 application里面运用我们设置的主题就可以改变颜色了。

4.3 如何改变光标的颜色

如果我们不做配置的话,EditText的光标的颜色是和系统的colorAccent的颜色一样的,给editText设置光标颜色只需要设置一个属性即可。

 <style name="et_login_text" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:textCursorDrawable">@drawable/cursor_input_et</item>
 </style>

在XML中为这个editText运用这个style即可

4.4 如何设置最大数量限制?

这个只需要在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:counterMaxLength="11"
        app:counterEnabled="true"
        android:scrollbarAlwaysDrawHorizontalTrack="true"
        android:textColorHint="@color/colorHint"
        app:counterOverflowTextAppearance="@style/TextOverCount"
        app:errorTextAppearance="@style/text_input_login_error_style">

counterMaxLength 设置最大长度限制
counterEnabled 是否开启超出限制后的提示
counterOverflowTextAppearance 超出限制后hint 的颜色,以及EditText 下划线的颜色 16/11 提示文字的颜色以及提示字体的大小都是在这个里面设置的


image.png

4.5 密码功能的小眼睛的显示与隐藏?

随着互联网的发展,很多用户的密码会很长,很麻烦,在输入的时候提示密码不对,这时候需要动态的可以看到密码的显示和隐藏密码,这种功能在TextInputLayout出来之前我们都是通过去标记一个初始状态,然后点击图片的时候去改变状态,然后设置editText的内容为可见,有了TextInputLayout以后,我们只需要去设置不同状态下显示的图片就可以了,省去了显示眼睛不同状态下图片的复杂的业务逻辑,具体的代码如下:


image.png

login_pwd_eye_selector的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/close_eyes" android:state_checked="false" />
    <item android:drawable="@mipmap/open_eyes" android:state_checked="true" />
</selector>

下面为密码开关的一些属性。
app:passwordToggleEnabled:设置 password 开关是否可用。
app:passwordToggleTint:设置 password 开关图标的 tint 着色。
app:passwordToggleTintMode:设置 password tint 的模式。
app:passwordToggleDrawable:设置 password 开关图标。
setPasswordVisibilityToggleDrawable:设置 password 开关图标。
isPasswordVisibilityToggleEnabled:设置 password 开关图标 是否可见。
setPasswordVisibilityToggleTintList:设置 password 开关图标的 tint。
setPasswordVisibilityToggleTintMode:设置 password 开关图标的 tint 模式。
getPasswordVisibilityToggleDrawable:设置 password 开关图标。

4.6 使用过程中的请求验证码显示错位的问题

TextinputRegister.gif

在上图中可以看到TextInputLayout中有一个获取验证码的按钮,因为TextInputLayout里面只能有EditText以及EditText的子类,所以我们想把获取验证码的按钮放在里面是不可能的。
最开始的时候的解决方案是TextInputLayout 外面套一层 RelativeLayout,然后把获取验证码这个Button 在RelativeLayout里面居中,最后发现这样写确实可以,但是当这个输入框有错误提示的时候,这个RelativeLayout的高度会变高,那么这个时候按钮的位置会在输入框的线上,所以最后把这个高度居中改为了直接距离上部20dp,这样问题就解决了。

总结:TextInputLayout用在登录、注册页面效果还是挺好的,但是就是一个TextInputLayout占用的高度很高,所以并不适合在很多输入框的页面上,本文的代码均是从实际业务中抽离出来的,可以直接拿去用,代码详见文章开头的GitHub地址。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容