前言
TextInputLayout可以輕松與EditText結(jié)合實現(xiàn)一些炫酷的效果辕近,例如一些常見的:
- Hint動畫
- 錯誤提示
- 字數(shù)計數(shù)
基本使用
首先需要有一個布局:
<android.support.design.widget.TextInputLayout
android:id="@+id/til_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintAnimationEnabled="true">
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入用戶名"/>
</android.support.design.widget.TextInputLayout>
hintAnimationEnabled屬性是設置是否開啟Hint的動畫。
需要注意的是骑丸,TextInputLayout必須包含一個EditText。
下面是一個基本的例子:
public class TextInputMainActivity extends AppCompatActivity {
private TextInputLayout til_input;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_input);
til_input = (TextInputLayout) findViewById(R.id.til_input);
til_input.getEditText().addTextChangedListener(new MaxTextTextWatcher(til_input, "字數(shù)不能大于6", 6));
//開啟計數(shù)
til_input.setCounterEnabled(true);
til_input.setCounterMaxLength(6);
}
class MaxTextTextWatcher implements TextWatcher {
private TextInputLayout mTextInputLayout;
private String mErrorString;
private int maxTextCount;
public MaxTextTextWatcher(TextInputLayout textInputLayout, String errorString, int maxTextCount) {
mTextInputLayout = textInputLayout;
mErrorString = errorString;
this.maxTextCount = maxTextCount;
}
@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) {
String str = mTextInputLayout.getEditText().getText().toString().trim();
if (!TextUtils.isEmpty(str)) {
if (str.length() > maxTextCount) {
//顯示錯誤
//設置錯誤提示
mTextInputLayout.setError(mErrorString);
mTextInputLayout.setErrorEnabled(true);
} else {
//關閉錯誤
mTextInputLayout.setErrorEnabled(false);
}
}
}
}
}
在這個例子里面芯杀,我們利用了TextInputLayout的錯誤提示肤舞、字數(shù)統(tǒng)計功能,基本的使用都比較簡單项炼。
- 在TextInputLayout可以輕松地通過getEditText方法找到它所包裹的EditText担平。、
- 在顯示錯誤的時候锭部,需要先設置錯誤的提示暂论,每次顯示的時候都要設置。
- 大部分屬性都可以通過xml的方式設置拌禾,這里通過代碼動態(tài)設置只是為了方便演示取胎。
TextInputLayout源碼分析
作為一個父容器,TextInputLayout繼承了線性布局:
public class TextInputLayout extends LinearLayout {
}
下面來看看它的構(gòu)造函數(shù):
public TextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
//檢查主題是不是AppCompatTheme
ThemeUtils.checkAppCompatTheme(context);
//設置線性布局的布局方向
setOrientation(VERTICAL);
setWillNotDraw(false);
setAddStatesFromChildren(true);
//添加輸入框的幀布局
mInputFrame = new FrameLayout(context);
mInputFrame.setAddStatesFromChildren(true);
addView(mInputFrame);
//Hint的動畫相關湃窍,包括字體大小以及顏色的變化動畫
mCollapsingTextHelper.setTextSizeInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
mCollapsingTextHelper.setPositionInterpolator(new AccelerateInterpolator());
mCollapsingTextHelper.setCollapsedTextGravity(Gravity.TOP | GravityCompat.START);
mHintExpanded = mCollapsingTextHelper.getExpansionFraction() == 1f;
//初始化一些參數(shù)
}
其中闻蛀,我們關心一下 顏色漸變的核心代碼:
/**
* Blend {@code color1} and {@code color2} using the given ratio.
*
* @param ratio of which to blend. 0.0 will return {@code color1}, 0.5 will give an even blend,
* 1.0 will return {@code color2}.
*/
private static int blendColors(int color1, int color2, float ratio) {
final float inverseRatio = 1f - ratio;
float a = (Color.alpha(color1) * inverseRatio) + (Color.alpha(color2) * ratio);
float r = (Color.red(color1) * inverseRatio) + (Color.red(color2) * ratio);
float g = (Color.green(color1) * inverseRatio) + (Color.green(color2) * ratio);
float b = (Color.blue(color1) * inverseRatio) + (Color.blue(color2) * ratio);
return Color.argb((int) a, (int) r, (int) g, (int) b);
}
這個方法就是根據(jù)ratio摄杂,返回一個顏色值。如果是0循榆,那么返回color1析恢,如果是1,那么返回color2秧饮。這是一個線性變化的過程映挂。
重寫addView了,如果是EditText盗尸,那么就需要手動生成一個幀布局:
@Override
public void addView(View child, int index, final ViewGroup.LayoutParams params) {
if (child instanceof EditText) {
mInputFrame.addView(child, new FrameLayout.LayoutParams(params));
// Now use the EditText's LayoutParams as our own and update them to make enough space
// for the label
mInputFrame.setLayoutParams(params);
updateInputLayoutMargins();
setEditText((EditText) child);
} else {
// Carry on adding the View...
super.addView(child, index, params);
}
}
另外TextInputLayout是通過兩種方式添加文字的柑船,一種是直接利用畫筆畫布繪制,一種是直接new一個TextView泼各,這也是我們自定義View的基本功鞍时。
TextInputLayout內(nèi)部就已經(jīng)給EditText添加了TextWatcher,用于字數(shù)的處理:
mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
updateLabelState(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) {}
});
如果覺得我的文字對你有所幫助的話扣蜻,歡迎關注我的公眾號:
我的群歡迎大家進來探討各種技術與非技術的話題逆巍,有興趣的朋友們加我私人微信huannan88,我拉你進群交(♂)流(♀)莽使。