Android Material Design之TextInputLayout

jlxg2181 8年前發布 | 29K 次閱讀 Android開發 移動開發 Material Design

最近在使用知乎Android客戶端的時候發現一個十分好玩的UI。如下圖:

圖1

其實不難看出,知乎app使用了大量原生的Android Material Design控件,包括ToolBar、DrawerLayout、NavigationView、CardView、SwipeRefreshLayout、FloatingActionButton、BottomNavigationBar等等等等。

順著這個思路,我很快找到上圖這個EditText獲取到焦點后,hint文本的動畫效果實際上也是來源于Material Design庫中的一個控件—— TextInputLayout 。下面簡單介紹一下這個控件的用法以及用途。

1 使用

1.1 添加庫依賴

要使用這個控件,需要引入 appcompat-v7 以及 Design Support Library 兩個庫。

dependencies {
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
}

1.2 布局中的使用

首先我們必須了解的是, TextInputLayout 繼承于 LinearLayout ,只能擁有一個直接的ChildView(類似于 ScrollView ),且這個ChildView只能是 EditText 。

<android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/edt_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="password"/>
    </android.support.design.widget.TextInputLayout>

一般來說, EditText 有一個 hint 屬性,當 Edittext 中沒有內容時,就會顯示文字提示。一旦用戶開始輸入時,這個文字提示就會消失,取而代之地顯示用戶的輸入。這樣有一個壞處就是用戶就無法了解到當前自己輸入的是關于什么的信息。

而TextInputLayout解決了這個問題,用戶開始輸入時, hint 文字提示會變成 EditText 上方的標簽,并伴隨一個向上平移+縮放的優雅動畫。

就這樣,就可以實現圖1的效果。

1.3 其他

  1. Google將 Design Support Library 設計得盡善盡美。庫中每個控件的設計顏色都來自 style.xmltheme 指定的各種顏色。在工程應用的主題中,修改 colorAccent 屬性便可以指定 TextInputLayout 的標簽字體顏色以及 EditText 的下劃線顏色。
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
     <item name="colorAccent">#3498db</item>
    </style>
  2. 實際項目中,我們需要對用戶的輸入進行校驗(例如 郵箱格式、密碼長度、手機號碼等),對用戶的輸入(即 mTextInputLayout.getEditText().getText().toString() )在后臺進行驗證,如果檢查到用戶輸入不合法,可以通過 setError() 顯示輸入錯誤提示,以及 setErrorEnabled(fasle) 清除錯誤提示。

    public void onClick(View v) {
     hideKeyboard();
    
     String username = usernameWrapper.getEditText().getText().toString();
     String password = usernameWrapper.getEditText().getText().toString();
     if (!validateEmail(username)) {
         usernameWrapper.setError("Not a valid email address!");
     } else if (!validatePassword(password)) {
         passwordWrapper.setError("Not a valid password!");
     } else {
         usernameWrapper.setErrorEnabled(false);
         passwordWrapper.setErrorEnabled(false);
         doLogin();
     }
    }
    `

正常狀態.png

錯誤提示的效果是:標簽字體顏色變紅,且在EditText下方出現錯誤信息的標簽,這時整個TextInputLayout的高度也會發生變化。如下圖:

錯誤提示.png

2 內部實現

/**
 * Layout which wraps an {@link android.widget.EditText} (or descendant) to show a floating label
 * when the hint is hidden due to the user inputting text.
 *
 * Also supports showing an error via {@link #setErrorEnabled(boolean)} and
 * {@link #setError(CharSequence)}.
 */
public class TextInputLayout extends LinearLayout {
      ......
    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (child instanceof EditText) {
            setEditText((EditText) child);
            super.addView(child, 0, updateEditTextMargin(params));
        } else {
            // Carry on adding the View...
            super.addView(child, index, params);
        }
    }

   private void setEditText(EditText editText) {

// Add a TextWatcher so that we know when the text input has changed
        mEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void afterTextChanged(Editable s) {
                updateLabelVisibility(true);
                if (mCounterEnabled) {
                    updateCounter(s.length());
                }
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

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

可以看出,TextInputLayout為內部的EditText設置了一個監聽器,監聽到有文本輸入的時候,通過 updateLabelVisibility(true); 將EditText的hint轉變成上方的標簽。

private void updateLabelVisibility(boolean animate) {
......
        if (hasText || isFocused || isErrorShowing) {
            // We should be showing the label so do so if it isn't already
            collapseHint(animate);
        } else {
            // We should not be showing the label so hide it
             expandHint(animate);
        }
}

而在 collapseHint(boolean animate) 和 expandHint(boolean animate) 內部都是執行 animateToExpansionFraction(final float target) 方法,通過屬性動畫來控制TextInputLayout里面EditText上方hint標簽的顯示。

private void animateToExpansionFraction(final float target) {
......
        mAnimator.setFloatValues(mCollapsingTextHelper.getExpansionFraction(), target);
        mAnimator.start();
    }

3 Conclusion

TextInputLayout的簡單使用,是Google推出的整個Material Design庫的一個縮影:Google將UI視覺效果設計得華麗且流暢,同時代碼封裝更為優雅,開發者只需要在layout.xml中寫好布局文件,就可以輕松在手機屏幕上展現出魔法般的動畫效果,實在是妙不可言。

 

來自:http://www.jianshu.com/p/dad372912dd5

 

 本文由用戶 jlxg2181 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!