TextInputLayout與TextInputEditText詳解

導讀:

Android 從5.0版本開始,新增了Android Materia Design庫,讓開發者高效的實現炫酷的UI效果

本篇文章將介紹Materia Design庫的TextInputLayout與TextInputEditText組件

TextInputLayout

  • TextInputLayout用於輔助EditText,當用戶輸入文本時,在EditText上方顯示浮動標籤,這個標籤的內容就是我們設置的android:hint屬性.

  • TextInputLayout 屬於Android Design Support library,可以直接向下兼容到Android 2.2.

  • TextInputLayout 繼承於Linerlayout,說明它是一個佈局,需要配合子控件使用才能顯示想要的效果,類似ScrollView的用法

TextInputLayout 屬性說明

屬性 說明
app:Theme 設置下劃線或其他的顏色屬性
android.support.design:counterEnabled 是否顯示計數器
android.support.design:counterMaxLength 設置計數器的最大值,與counterEnabled同時使用
android.support.design:counterTextAppearance 計數器的字體樣式
android.support.design:counterOverflowTextAppearance 輸入字符大於我們限定個數字符時的字體樣式
android.support.design:errorEnabled 是否顯示錯誤信息
android.support.design:errorTextAppearance 錯誤信息的字體樣式
android.support.design:hintAnimationEnabled 是否顯示hint的動畫,默認true
android.support.design:hintEnabled 是否使用hint屬性,默認true
android.support.design:hintTextAppearance 設置hint的文字樣式(指運行動畫效果之後的樣式)
android.support.design:passwordToggleDrawable 設置密碼開關Drawable圖片,於passwordToggleEnabled同時使用
android.support.design:passwordToggleEnabled 是否顯示密碼開關圖片,需要EditText設置inputType
android.support.design:passwordToggleTint 設置密碼開關圖片顏色
android.support.design:passwordToggleTintMode 設置密碼開關圖片(混合顏色模式),與passwordToggleTint同時使用

TextInputLayout使用

一、moudle的bulid.gradle 添加依賴庫:


dependencies {
 compile 'com.android.support:appcompat-v7:25.3.1'
 compile 'com.android.support:design:26.0.0-alpha1'
 }

二、XML佈局文件設置屬性


<?xml version="1.0" encoding="utf-8"?>
<!-- xmlns:app="http://schemas.android.com/apk/res-auto" 記得設置命名空間-->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="xmx.zs.materia_design.TextInputLayoutActivity">

    <!--android.support.design:hintAnimationEnabled | 是否顯示hint的動畫,默認true-->
    <!--android.support.design:hintEnabled | 是否使用hint屬性,默認true-->
    <!--android.support.design:hintTextAppearance | 設置hint的文字樣式(指運行動畫效果之後的樣式)-->
    <!--android.support.design:counterEnabled | 是否顯示計數器-->
    <!--android.support.design:counterMaxLength | 設置計數器的最大值-->
    <!--android.support.design:counterOverflowTextAppearance | 輸入字符大於我們限定個數字符時的樣式-->
    <!--app:theme 設置浮動標籤的顏色主題-->
    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:counterEnabled="true"
        app:counterMaxLength="5"
        app:counterOverflowTextAppearance="@style/OverTextAppearance"
        app:counterTextAppearance="@style/CountTextAppearance"
        app:hintAnimationEnabled="false"
        app:hintEnabled="true"
        app:hintTextAppearance="@style/EditText_hintTextAppearance"
        app:theme="@style/EditText_Theme">

        <!--EditText 設置左側圖片,系統建議drawableStart/drawableLeft一起用,API>17-->
        <android.support.design.widget.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawableLeft="@mipmap/edit_account"
            android:drawableStart="@mipmap/edit_account"
            android:hint="請輸入用戶名"
            android:imeOptions="actionNext"
            android:inputType="text"/>

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

    <!--android.support.design:passwordToggleEnabled | 是否顯示密碼開關圖片,需要EditText設置inputType-->
    <!--android.support.design:passwordToggleTint | 設置密碼開關圖片顏色-->
    <!--android.support.design:passwordToggleTintMode | 設置密碼開關圖片(混合顏色模式),與passwordToggleTint同時使用-->
    <!--android.support.design:errorEnabled |是否顯示錯誤信息-->
    <!--android.support.design:errorTextAppearance| 錯誤信息的字體樣式-->

    <!--系統默認的密碼開關(修改顏色主題)-->
    <android.support.design.widget.TextInputLayout
        android:id="@+id/til"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入密碼"
        app:counterEnabled="true"
        app:counterMaxLength="5"
        app:counterOverflowTextAppearance="@style/OverTextAppearance"
        app:counterTextAppearance="@style/CountTextAppearance"
        app:errorEnabled="true"
        app:errorTextAppearance="@style/ErrorTextAppearance"
        app:passwordToggleEnabled="true"
        app:passwordToggleTint="@color/colorPrimaryDark"
        app:passwordToggleTintMode="multiply"
        app:theme="@style/EditText_Theme">

        <EditText
            android:id="@+id/editText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawableLeft="@mipmap/edit_lock"
            android:drawableStart="@mipmap/edit_lock"
            android:imeOptions="actionNext"
            android:inputType="textPassword"
            android:paddingLeft="100dp"/>

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

    <!--android.support.design:passwordToggleDrawable | 設置密碼開關Drawable圖片-->
    <!--自定義我們的密碼開關圖片(drawable)-->
    <android.support.design.widget.TextInputLayout
        android:id="@+id/til_customize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請確認密碼"
        app:counterEnabled="true"
        app:counterMaxLength="5"
        app:passwordToggleDrawable="@drawable/password_visible_invisible"
        app:passwordToggleEnabled="true"
        >

        <android.support.design.widget.TextInputEditText
            android:id="@+id/editText_customize"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawableLeft="@mipmap/edit_lock"
            android:drawableStart="@mipmap/edit_lock"
            android:imeOptions="actionDone"
            android:inputType="textPassword"/>


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

    <!--Test EditText.setCompoundDrawables()-->
    <android.support.design.widget.TextInputLayout
        android:id="@+id/til_testEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:passwordToggleDrawable="@drawable/password_visible_invisible"
        >

        <EditText
            android:id="@+id/editText_drawable"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawableLeft="@mipmap/edit_lock"
            android:drawableStart="@mipmap/edit_lock"
            android:hint="Test EditText.setCompoundDrawables()"
            android:inputType="numberPassword"/>
    </android.support.design.widget.TextInputLayout>

    <!--Test EditText.setCompoundDrawablesWithIntrinsicBounds()-->
    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:passwordToggleDrawable="@drawable/password_visible_invisible">

        <EditText
            android:id="@+id/editText_drawable2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Test EditText.setCompoundDrawablesWithIntrinsicBounds()"
            android:inputType="numberPassword"/>
    </android.support.design.widget.TextInputLayout>


</LinearLayout>

三、MainActivity中調用控件

其實做完上面兩步就已經有效果了,這裏簡單的演示下:

  • EditText.setError()和TextInputLayout.setError()的簡單監聽

  • EditText.setCompoundDrawables()和EditText.setCompoundDrawablesWithIntrinsicBounds()的簡單使用

/*
 * @創建者     默小銘
 * @博客       http://blog.csdn.net/u012792686
 * @創建時間   2017/6/10
 * @本類描述      TextInputLyout 實際使用例子
 * @內容說明   
 * @補充內容
 *
 * ---------------------------------
 * @更新時間
 * @新增內容
 *
 */
public class TextInputLayoutActivity extends AppCompatActivity {

    private TextInputEditText mEditText_customize;
    private TextInputLayout   mTil_customize;
    private EditText          mEditText;
    private TextInputLayout   mTextInputLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_text_input_layout);

        //自定義密碼開關輸入框
        mEditText_customize = (TextInputEditText) findViewById(R.id.editText_customize);
        mTil_customize = (TextInputLayout) findViewById(R.id.til_customize);
        //系統自帶的密碼開關輸入框
        mEditText = (EditText) findViewById(R.id.editText);
        mTextInputLayout = (TextInputLayout) findViewById(R.id.til);
        testSetCompoundDrawables();
        testSetCompoundDrawablesWithIntrinsicBounds();
        customizeEditText();
        TextInputLyout_EditText();

    }

    /**
     * 測試EditText.setCompoundDrawablesWithIntrinsicBounds()
     * <p>
     * 可以在上、下、左、右設置圖標,如果不想在某個地方顯示,則設置爲null。
     * <p>
     * 圖標的寬高將會設置爲固有寬高,既自動通過getIntrinsicWidth和getIntrinsicHeight獲取。
     * <p>
     * 即:這種方式只能顯示原圖
     */
    private void testSetCompoundDrawablesWithIntrinsicBounds() {
        Drawable drawable = getResources().getDrawable(R.mipmap.edit_lock);
        EditText editText_drawable = (EditText) findViewById(R.id.editText_drawable2);
        editText_drawable.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);

    }

    /**
     * 測試EditText.setCompoundDrawables()
     * <p>
     * 可以在上、下、左、右設置圖標,如果不想在某個地方顯示,則設置爲null。
     * <p>
     * 但是Drawable必須要setBounds(Rect)。設置初始位置、寬和高等信息。
     * <p>
     * 即:使用前要先調用Drawable.setBounds(),可以調整圖片的大小和相對位置
     */
    private void testSetCompoundDrawables() {
        Drawable drawable = getResources().getDrawable(R.mipmap.edit_lock);
        drawable.setBounds(0, 0, 40, 40);
        EditText editText_drawable = (EditText) findViewById(R.id.editText_drawable);
        editText_drawable.setCompoundDrawables(drawable, null, null, null);
    }

    /**
     * 系統自帶的密碼開關輸入框的錯誤信息處理
     */
    private void TextInputLyout_EditText() {
        mEditText.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) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (mEditText.getText().length() > mTextInputLayout.getCounterMaxLength()) {
                    mTextInputLayout.setError("超出限定字數了...");
                }

            }
        });

    }

    /**
     * 自定義密碼開關輸入框的錯誤信息處理
     */
    private void customizeEditText() {
        mEditText_customize.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) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (mEditText_customize.getText().length() > mTil_customize.getCounterMaxLength()) {
                    mEditText_customize.setError("超出限定字數了!!");
                }
            }
        });


    }
}

Demo效果圖

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

==注意==

  1. 添加庫的時候注意要加appcompat-v7庫,確保可以向後兼容
  2. TextInputLayout下的實際視圖層次結構不能保證以XML格式編寫視圖層次結構。 因此,對於TextInputLayout的子對象EditText(或子類TextInputEditText)想調用getParent()可能不會返回TextInputLayout. 如果您需要直接訪問視圖,建議設置一個android:id並使用findViewById(int).
  3. 一個TextInputLayout只能套一個EditText(或它的子類TextInputEditText)
  4. 當使用passwordToggleDrawable密碼開關圖片的時候,EditText end位置的 圖標時會被覆蓋的,爲了保證EditText end 位置Drawable的正常顯示,你需要在設置這些Drawables 的相對位置(start/end)爲絕對(left/right).(官方文檔說的,沒搞懂)
  5. 使用了TextInputLayout,和它的setError(),佈局所佔的位置會變多,設計佈局注意留適當的空間
  6. EditText的setError和passwordToggleDrawable的圖片會重疊,建議只用TextInputLatyout的setError或者重寫EditText的佈局,抉擇一個吧
  7. TextInputLayout.setError()注意調用setErrorEnabled(false)清空錯誤信息,不然會一直顯示
  8. 建議TextInputLayout只套一個EditText,放其他控件會出現焦點搶佔的問題(View的事件分發)

TextInputEditText

  • TextInputEditText是EditText的子類,說白了是爲了填EditText的坑的

  • 當我們的界面處於全屏時,點擊一個EditText,默認情況下不是在它下面彈出鍵盤,而是進入到輸入法的一個全屏的輸入界面(通過配置android:imeOptions=”flagNoExtractUi”可以設爲直接在當前界面顯示)

  • 如果我們給EditText 套上了一個TextInputLayout時,TextInputLayout會拿到EditText的hint顯示出來並把EditText本身的hint設爲空.這樣我們在全屏的輸入界面上,就顯示不出來我們設置hint,因此TextInputEditText重寫了EditText

小知識:EditText的imeOptions要與inputType同時使用,不然沒有反應

EditText與TextInputEditText效果區別圖

這裏寫圖片描述

在EditText 設置android:drawableLeft Bug

  • 今天在TextInputLayout設置了app:passwordToggleEnabled=”true”屬性的EditText設置androd:drawableLeft屬性時發現,只能顯示原圖,然後在代碼調用Drawable.setBounds()方式調整大小時,發現drawableLeft圖片直接不顯示了(估計源碼沒設計好)

  • 而不調用 app:passwordToggleEnabled=”true”屬性,Drawable.setBounds()能正常使用

  • 因此建議同學們,要麼使用原圖(美工切小圖),要麼不用passwordToggleEnabled屬性,自己自定義drawableLeft/drawableRight(建議)

TextInputLayout使用bug:

  • 今天使用TextInputLyout.setError()發現以下bug,
Failed to inflate ColorStateList, leaving it to the framework
    java.lang.RuntimeException: Failed to resolve attribute at index 0
    android.content.res.TypedArray.getColor(TypedArray.java:401)
    ...

解決:
在佈局文件的TextInputLayout設置app:errorTextAppearance=”@style/Theme.AppCompat”,同學們使用過程中發現類似RuntimeException bug,同理設置樣式即可解決

總結

本篇文章Demo

留個TODO,請求大神幫幫忙:

當使用passwordToggleDrawable密碼開關圖片的時候,EditText end位置的 圖標時會被覆蓋的,爲了保證EditText end 位置Drawable的正常顯示,你需要在設置這些Drawables 的相對位置(start/end)爲絕對(left/right).(官方文檔說的,沒搞懂)

官方用的矢量圖,自己的方案是找個寬高較小的圖片,或者重寫EditText,自定義View

本篇文章到此結束,歡迎關注,後續有補充的會即使更新,有問題也歡迎評論,共同成長

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章