參考了Google官方培訓(xùn)課程和鴻洋大神的博客,下面進(jìn)入正題
Googl官方建議
·遵守Android標(biāo)準(zhǔn)規(guī)則吨些。
·提供自定義的風(fēng)格屬性值并能夠被Android XML Layout所識(shí)別
·發(fā)出可訪(fǎng)問(wèn)的事件搓谆。
·能夠兼容Android的不同平臺(tái)。
常用實(shí)現(xiàn)2種方式
·繼承View
·拓展現(xiàn)有控件(繼承系統(tǒng)提供的UI組件)
自定義View的流程
1.繼承View或者繼承View的一個(gè)實(shí)現(xiàn)類(lèi)
- 至少重寫(xiě)父類(lèi)的一個(gè)構(gòu)造方法
它包含一個(gè)Contenx與一個(gè)AttributeSet對(duì)象作為參數(shù)豪墅。這個(gè)constructor允許layout editor創(chuàng)建并編輯你的view的實(shí)例泉手。
public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
getAttrs(context,attrs);
}
2.定義自定義屬性
Gogle官方建議:
·為你的view在資源標(biāo)簽下定義自設(shè)的屬性
·在你的XML layout中指定屬性值
·在運(yùn)行時(shí)獲取屬性值
·把獲取的屬性值應(yīng)用到你的view上如何定義?
在vuales文件夾下新建attrs.xml文件偶器,定義自定義View需要的屬性斩萌,可以通過(guò)構(gòu)造方法的 atts參數(shù)獲取
<resources>
<declare-styleable name="RoundImageView">
<attr name="XfermodeImageView_src" format="reference"/>
<attr name="XfermodeImageView_type" format="integer"/>
<attr name="XfermodeImageView_borderRadius" format="dimension"/>
</declare-styleable>
</resources>-
如何使用缝裤?
在使用自定義的屬性時(shí)要聲明相應(yīng)的命名空間:<com.wenjie.drawview.RoundImageView xmlns:custom="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" custom:XfermodeImageView_src="@mipmap/test2" />
請(qǐng)注意:如果你的view是一個(gè)inner class,你必須指定這個(gè)view的outer class.同樣的,如果PieChart有一個(gè)inner class叫做PieView颊郎。為了使用這個(gè)類(lèi)中自設(shè)的屬性憋飞,你應(yīng)該使用com.example.customviews.charting.PieChart$PieView.
-
如何獲取屬性并且應(yīng)用?
對(duì)res目錄里的每一個(gè)<declare-styleable>資源姆吭,自動(dòng)生成的R.java文件定義了存放屬性ID的數(shù)組和常量榛做,常量用來(lái)索引數(shù)組中每個(gè)屬性。因此我們可以使用TypedArray這個(gè)類(lèi)來(lái)讀取屬性:(為了方便内狸,下面的代碼比較簡(jiǎn)單)
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.CustomView,
0, 0);
try {
mShowText =a.getBoolean(R.styleable.CustomView_showText, false);
mTextPos = a.getInteger(R.styleable.CustomView_labelPosition, 0);
} finally {
a.recycle();
}
}
TypedArray對(duì)象是一個(gè)共享資源检眯,必須被在使用后進(jìn)行回收。
-
添加屬性和事件
public boolean isShowText() {
return mShowText;
}public void setShowText(boolean showText) { mShowText = showText; invalidate(); requestLayout(); }
注意點(diǎn):在setShowText方法里面有調(diào)用invalidate()) and requestLayout()). 這兩個(gè)調(diào)用是確保穩(wěn)定運(yùn)行的關(guān)鍵答倡。當(dāng)view的某些內(nèi)容發(fā)生變化的時(shí)候轰传,需要調(diào)invalidate來(lái)通知系統(tǒng)對(duì)這個(gè)view進(jìn)行redraw,當(dāng)某些元素變化會(huì)引起組件大小變化時(shí)瘪撇,需要調(diào)用requestLayout方法获茬。調(diào)用時(shí)若忘了這兩個(gè)方法,將會(huì)導(dǎo)致hard-to-find bugs倔既。
- 響應(yīng)事件的監(jiān)聽(tīng)器
如果需要額外的事件恕曲,可以通過(guò)接口回調(diào)的方式來(lái)設(shè)置事件監(jiān)聽(tīng),一般可以定義一個(gè)內(nèi)部接口.
3.需要warp_content屬性時(shí):在onMeasure()方法中判斷測(cè)量模式為AT_MOST時(shí)渤涌,設(shè)定一個(gè)值佩谣。
4.實(shí)現(xiàn)onDraw()方法:在這里繪制