目前代碼已經(jīng)上傳到GitHub,里面有博客里面Material Design系列的所有代碼
GitHub Material Design
1速梗、什么是TextInputLayout籍茧?
TextInputLayout是22.2.0新添加的控件版述, 要和EditText(或EditText的子類)結(jié)合使用,并且只能包含一個(gè)EditText(或EditText的子類)寞冯,這一點(diǎn)尤其重要院水,在做用戶注冊(cè)的時(shí)候遇到了TextInputLayout里面有獲取驗(yàn)證碼的按鈕,布局的時(shí)候出現(xiàn)問(wèn)題了简十,具體的解決方法詳見(jiàn)下文,TextInputLayout的繼承關(guān)系如下圖所示撬腾。
2螟蝙、為什么要用TextInputLayout?
遵循Material Design的設(shè)計(jì)民傻,很多APP在用戶登錄胰默、注冊(cè)的頁(yè)面中都使用了TextInputLayout的控件,在一些iOS的APP中也能發(fā)現(xiàn)這種想過(guò)漓踢,通過(guò)一些細(xì)微的動(dòng)畫(huà)效果以及改變顏色牵署,能達(dá)到很炫酷的效果,相比傳統(tǒng)的EditText喧半,在用戶輸入信息的時(shí)奴迅,hint(提示)會(huì)自動(dòng)上移,并且輸入框的下劃線會(huì)高亮挺据,并能夠把輸入校驗(yàn)的錯(cuò)誤能夠在控件下面展示取具,不用Toast彈出提示,并且自帶設(shè)置密碼框的顯示與隱藏扁耐,效果如下圖所示暇检。
3、如何使用TextInputLayout婉称?
3.1 首先在build.gradle 引入design的庫(kù)
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="注冊(cè)"
android:textColor="#ff5c5f5f"
android:textSize="12dp" />
</RelativeLayout>
</RelativeLayout>
3.3在activity中的設(shè)置
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 達(dá)到上面效果我們需要做到的步驟
XML中配置的如上圖所示,這樣就可以基本完成TextInputLayout的功能了悔据,但是想使用TextInputLayout自帶的錯(cuò)誤提示功能庄敛,在代碼中還需要設(shè)置以下兩點(diǎn)。
4.1.1 需要給TextInputEditText添加 addTextChangedListener監(jiān)聽(tīng)蜜暑,當(dāng)文本有變化的時(shí)候需要?jiǎng)討B(tài)的去設(shè)置铐姚,整個(gè)項(xiàng)目都是用Kotlin寫(xiě)的,Java的寫(xiě)法也是一樣肛捍,只是語(yǔ)法不一樣隐绵。
text_input_layout_pwd.isErrorEnabled = false
4.1.2 校驗(yàn)錯(cuò)誤的時(shí)候去設(shè)置錯(cuò)誤提示
可以看到完成1、2點(diǎn)以后就可以使用TextInputLayout的錯(cuò)誤提示功能了
4.2 如何改變默認(rèn)的顏色拙毫,能夠適配自己APP顏色風(fēng)格的UI
如果我們不進(jìn)行顏色設(shè)置的話依许,那么我們字體的顏色以及下劃線的顏色一定和colorPrimary、colorPrimaryDark缀蹄、colorAccent顏色是一樣的峭跳。
<!-- 代表 hint 的顏色 -->
<item name="android:textColorHint">#ff6f7272</item>
<!-- 代表 下劃線沒(méi)有獲取焦點(diǎn)的顏色 的顏色 -->
<item name="colorControlNormal">#ffd8d8d8</item>
<!-- 代表 代表了獲取焦點(diǎn)的時(shí)候 下劃線 的顏色 -->
<item name="colorControlActivated">#ff3586fe</item>
<!-- 代表 代表了點(diǎn)擊的時(shí)候 下劃線 的顏色 -->
<item name="colorControlHighlight">#ff3586fe</item>
然后在我們的AndroidManifest.xml 里面的 application里面運(yùn)用我們?cè)O(shè)置的主題就可以改變顏色了。
4.3 如何改變光標(biāo)的顏色
如果我們不做配置的話缺前,EditText的光標(biāo)的顏色是和系統(tǒng)的colorAccent的顏色一樣的蛀醉,給editText設(shè)置光標(biāo)顏色只需要設(shè)置一個(gè)屬性即可。
<style name="et_login_text" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:textCursorDrawable">@drawable/cursor_input_et</item>
</style>
在XML中為這個(gè)editText運(yùn)用這個(gè)style即可
4.4 如何設(shè)置最大數(shù)量限制衅码?
這個(gè)只需要在TextInputLayout里面設(shè)置幾個(gè)屬性就可以了
<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 設(shè)置最大長(zhǎng)度限制
counterEnabled 是否開(kāi)啟超出限制后的提示
counterOverflowTextAppearance 超出限制后hint 的顏色拯刁,以及EditText 下劃線的顏色 16/11 提示文字的顏色以及提示字體的大小都是在這個(gè)里面設(shè)置的
4.5 密碼功能的小眼睛的顯示與隱藏?
隨著互聯(lián)網(wǎng)的發(fā)展逝段,很多用戶的密碼會(huì)很長(zhǎng)垛玻,很麻煩,在輸入的時(shí)候提示密碼不對(duì)奶躯,這時(shí)候需要?jiǎng)討B(tài)的可以看到密碼的顯示和隱藏密碼帚桩,這種功能在TextInputLayout出來(lái)之前我們都是通過(guò)去標(biāo)記一個(gè)初始狀態(tài),然后點(diǎn)擊圖片的時(shí)候去改變狀態(tài)嘹黔,然后設(shè)置editText的內(nèi)容為可見(jiàn)账嚎,有了TextInputLayout以后,我們只需要去設(shè)置不同狀態(tài)下顯示的圖片就可以了儡蔓,省去了顯示眼睛不同狀態(tài)下圖片的復(fù)雜的業(yè)務(wù)邏輯醉锄,具體的代碼如下:
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>
下面為密碼開(kāi)關(guān)的一些屬性。
app:passwordToggleEnabled:設(shè)置 password 開(kāi)關(guān)是否可用浙值。
app:passwordToggleTint:設(shè)置 password 開(kāi)關(guān)圖標(biāo)的 tint 著色恳不。
app:passwordToggleTintMode:設(shè)置 password tint 的模式。
app:passwordToggleDrawable:設(shè)置 password 開(kāi)關(guān)圖標(biāo)开呐。
setPasswordVisibilityToggleDrawable:設(shè)置 password 開(kāi)關(guān)圖標(biāo)烟勋。
isPasswordVisibilityToggleEnabled:設(shè)置 password 開(kāi)關(guān)圖標(biāo) 是否可見(jiàn)规求。
setPasswordVisibilityToggleTintList:設(shè)置 password 開(kāi)關(guān)圖標(biāo)的 tint。
setPasswordVisibilityToggleTintMode:設(shè)置 password 開(kāi)關(guān)圖標(biāo)的 tint 模式卵惦。
getPasswordVisibilityToggleDrawable:設(shè)置 password 開(kāi)關(guān)圖標(biāo)阻肿。
4.6 使用過(guò)程中的請(qǐng)求驗(yàn)證碼顯示錯(cuò)位的問(wèn)題
在上圖中可以看到TextInputLayout中有一個(gè)獲取驗(yàn)證碼的按鈕,因?yàn)門(mén)extInputLayout里面只能有EditText以及EditText的子類沮尿,所以我們想把獲取驗(yàn)證碼的按鈕放在里面是不可能的丛塌。
最開(kāi)始的時(shí)候的解決方案是TextInputLayout 外面套一層 RelativeLayout,然后把獲取驗(yàn)證碼這個(gè)Button 在RelativeLayout里面居中畜疾,最后發(fā)現(xiàn)這樣寫(xiě)確實(shí)可以赴邻,但是當(dāng)這個(gè)輸入框有錯(cuò)誤提示的時(shí)候,這個(gè)RelativeLayout的高度會(huì)變高啡捶,那么這個(gè)時(shí)候按鈕的位置會(huì)在輸入框的線上姥敛,所以最后把這個(gè)高度居中改為了直接距離上部20dp,這樣問(wèn)題就解決了瞎暑。