效果展示
從圖中可以看出這次自定義View的效果产镐。具體功能如下:
設(shè)置頭部文字的字體大小励堡、字體顏色鼻弧、文字內(nèi)容
設(shè)置輸入框的字體大小涩哟、字體顏色、文字內(nèi)容添履、提示文字
開始自定義
一郁轻、 第一步先新建一個(gè)類名為EditTextPlus(可自己命名)繼承FrameLayout的文件泥兰,因?yàn)槲覀円獙?shí)現(xiàn)在布局文件中能是用自己的屬性庄涡,所以我們還要在values目錄下新建attrs.xml文件(用于添加自定義的屬性)
二量承、在 attrs.xml 文件中添加如下屬性(其中除了字體的基本屬性之外,還包括了輸入框的輸入類型,鍵盤的類型等)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="EditTextPlus">
<attr name="head_title_text" format="string" />
<attr name="head_titile_text_size" format="dimension" />
<attr name="head_title_text_color" format="color" />
<attr name="edit_hint_text" format="string" />
<attr name="edit_text_size" format="dimension" />
<attr name="edit_text_color" format="color" />
<attr name="edit_input_type" format="enum">
<enum name="Text" value="0" />
<enum name="Phone" value="1" />
<enum name="Password" value="2" />
<enum name="Number" value="3" />
</attr>
<!-- 鍵盤類型 -->
<attr name="edit_editor_option" format="enum">
<enum name="IME_ACTION_NONE" value="0" />
<enum name="IME_ACTION_DONE" value="1" />
<enum name="IME_ACTION_GO" value="2" />
<enum name="IME_ACTION_NEXT" value="3" />
<enum name="IME_ACTION_PREVIOUS" value="4" />
<enum name="IME_ACTION_SEARCH" value="5" />
<enum name="IME_ACTION_SEND" value="6" />
<enum name="IME_ACTION_UNSPECIFIED" value="7" />
</attr>
</declare-styleable>
</resources>
那么添加了這些屬性之后要如何使用呢撕捍?如下圖所示:
其中最重要的是要使用下面那句話拿穴,才能使用自定義的屬性。(xmlns:app中的app命名可以任意)
xmlns:app="http://schemas.android.com/apk/res-auto"
三忧风、在布局文件中已經(jīng)使用了自定義的屬性默色,那么我們現(xiàn)在要做的就是如何解析相關(guān)屬性。所以我們回到EditTextPlus類中狮腿。
上圖為類中聲明的成員變量腿宰。
在解析的時(shí)候我們通過 AttributeSet 來獲得 TypeArray(注意: 必須要調(diào)用 recycle 方法進(jìn)行回收)
不同類型的屬性使用不同的方法來獲得,而且必須設(shè)置默認(rèn)值蚤霞,在用戶沒有設(shè)置屬性的時(shí)候,使用默認(rèn)值
其中通過 typedArray.getDimension 方法得到的參數(shù)單位為像素(px)义钉。在使用的時(shí)候要注意單位的轉(zhuǎn)化昧绣,所以在設(shè)置默認(rèn)值得時(shí)候,將 sp 轉(zhuǎn)化為 px
edit_editor_option 和 edit_input_type 為枚舉類型捶闸,在 attrs.xml 文件中聲明了每個(gè)枚舉對應(yīng)的 value
具體解析自定義屬性的代碼如下:
private void initAttr(AttributeSet attrs) {
Drawable background = getBackground();
//當(dāng)沒有設(shè)置background時(shí)使用默認(rèn)的background
if (null == background) {
setBackgroundResource(R.drawable.drawable_default_edittext_plus);
}
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.EditTextPlus);
//
mEditTextSize = typedArray.getDimension(R.styleable.EditTextPlus_edit_text_size, sp2px(mEditTextSize));
mEditHintText = typedArray.getString(R.styleable.EditTextPlus_edit_hint_text);
if (TextUtils.isEmpty(mEditHintText)) {
mEditHintText = "";
}
mEditTextColor = typedArray.getColor(R.styleable.EditTextPlus_edit_text_color,
ContextCompat.getColor(mContext, R.color.EditTextPlusDefaultTextColor));
mInputType = typedArray.getInt(R.styleable.EditTextPlus_edit_input_type, mInputType);
mEditorOption = typedArray.getInt(R.styleable.EditTextPlus_edit_editor_option, mEditorOption);
//
mHeadTextSize = typedArray.getDimension(R.styleable.EditTextPlus_head_titile_text_size, sp2px(mHeadTextSize));
mHeadText = typedArray.getString(R.styleable.EditTextPlus_head_title_text);
if (TextUtils.isEmpty(mHeadText)) {
mHeadText = "未設(shè)置";
}
mHeadTextColor = typedArray.getColor(R.styleable.EditTextPlus_head_title_text_color, mEditTextColor);
//
typedArray.recycle();
}
獲取屬性方法的調(diào)用順序如下
在一個(gè)參數(shù)構(gòu)造方法中調(diào)用兩個(gè)參數(shù)的構(gòu)造方法夜畴,在兩個(gè)參數(shù)的構(gòu)造方法中調(diào)用三個(gè)參數(shù)的構(gòu)造方法。這樣子所有的構(gòu)造方法都會(huì)經(jīng)過三個(gè)參數(shù)的構(gòu)造方法
在構(gòu)造方法中填充布局删壮,調(diào)用 initAttr 得到各個(gè)屬性的值贪绘,再調(diào)用 initView 設(shè)置對應(yīng)屬性的值。
四央碟、既然設(shè)置自定義屬性的值税灌,并且屬性都設(shè)置到相應(yīng)的位置。最后一個(gè)問題亿虽,就是如何將自定義View中的事件傳輸出去菱涤,如:刪除按鈕的點(diǎn)擊事件。
- 在類中聲明接口
public interface OnDeleteListener {
void onDelete();
}
- 在類中聲明成員變量 onDeleteListener
-
聲明變量的 set 方法
public void setOnDeleteListener(OnDeleteListener onDeleteListener) { this.onDeleteListener = onDeleteListener; }
-
在 initView 中設(shè)置點(diǎn)擊事件洛勉,并判斷是否聲明的 onDeleteListener 是否為空粘秆,不為空則調(diào)用接口中的方法
ivDelete.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { etInput.setText(""); if (mHasDeleteAnimator) { //為了實(shí)現(xiàn)在點(diǎn)擊刪除時(shí),控件左右抖動(dòng)的效果 EditTextPlus.this.animate().translationX(5).setInterpolator(new CycleInterpolator(3)).setDuration(500).start(); } if (null != onDeleteListener) { onDeleteListener.onDelete(); } } });
使用該接口的時(shí)候就相當(dāng)于設(shè)置系統(tǒng)控件的點(diǎn)擊事件一樣收毫,調(diào)用 setOnDeleteListener 方法攻走。
GitHub地址: EditextDemo