咱們在寫界面佈局的xml時,常常要設置組件的屬性,好比經常使用的java
android:id="@+id/id_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
複製代碼
而假如咱們須要對自定義的view、viewgroup等等添加自定義的屬性呢?就是須要typedarray了。此次咱們的例子是給自定義的view添加屬性。android
code警告canvas
public class ViewWithAttrs extends View {
public ViewWithAttrs(Context context, AttributeSet attrs){
super(context, attrs);
}
}
複製代碼
<resources>
<declare-styleable name="ViewWithAttrs">
<attr name="paint_color" format="color"/>
</declare-styleable>
</resources>
複製代碼
注意第二行的name="ViewWithAttrs",name就是你要添加屬性的組件,必定要和view名字相同。緩存
而後就是添加咱們想要的屬性了,這裏我添加了一條屬性,屬性名是"paint_color",這個是本身定義的,屬性類型是:color。app
還有其餘可選的類型有:ide
reference 表示引用,參考某一資源ID
string 表示字符串
color 表示顏色值
dimension 表示尺寸值
boolean 表示布爾值
integer 表示整型值
float 表示浮點值
fraction 表示百分數
enum 表示枚舉值
flag 表示位運算佈局
經過Contex的obtainStyledAttributes方法建立typedarray,而後用getXXX來獲取對應的屬性。測試
show me the codeui
public class ViewWithAttrs extends View {
private Paint mPaint;
public ViewWithAttrs(Context context, AttributeSet attrs){
super(context, attrs);
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
//首先經過obtainStyledAttributes方法獲取typedarray
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.ViewWithAttrs);
//使用typedarray獲取對應的屬性
int paintColor = typedArray.getColor(R.styleable.ViewWithAttrs_paint_color, Color.BLACK);
//最後的Color.BLACK是沒獲取到時的默認值
mPaint.setColor(paintColor);
typedArray.recycle();//不要忘記回收!
}
}
複製代碼
這樣咱們獲取到了咱們想要的屬性,能夠在這個View中使用了idea
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawCircle(200,200,50,mPaint);
}
複製代碼
在MainActivity的佈局文件activity_main.xml中添加咱們的view並設置好屬性
<com.idealcountry.test.ViewWithAttrs
android:id="@+id/id_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:paint_color="@color/blue"/>
複製代碼
這樣咱們就能在代碼中獲取xml設置好的paint_color了。//這裏我在color.xml中註冊了一個顏色:color/blue
結果圖:
小德我在寫自定義的View時,剛開始定義了一個類的屬性用來保存從AttributeSet獲取的typedarray,可是手滑了把獲取typedarray寫到了onDraw()方法裏了,測試的時候後發現沒有成功獲取到xml中定義的屬性,經過debug這才知道在onDraw方法中拿到的值是空的,採用了默認值。可是這是爲何呢?
通過查找到layoutInflater這個類才清楚,大概意思就是AttributeSet並非每一個View都分配一個,而是有相似於緩存同樣的機制,你們是共用的(大概能夠這麼理解),因此到ondraw就有可能獲取到了不是咱們須要的AttributeSet了。
爲何必定要強調回收呢?這東西又不是佔了線程,我就不回收能怎麼樣?(其實不回收的話AS也會一直煩你,說你沒有回收)
爲了弄清楚,咱們須要進入源碼來看一看。幾回goto declaration,咱們最終在Typedarray.java中找到了,注意這個靜態方法裏的第一句。
static TypedArray obtain(Resources res, int len) {
TypedArray attrs = res.mTypedArrayPool.acquire();
if (attrs == null) {
attrs = new TypedArray(res);
}
attrs.mRecycled = false;
// Reset the assets, which may have changed due to configuration changes
// or further resource loading.
attrs.mAssets = res.getAssets();
attrs.mMetrics = res.getDisplayMetrics();
attrs.resize(len);
return attrs;
}
複製代碼
並且這個類的構造方法隱藏了,是protected的,很明顯的一個單例模式。
/** @hide */
protected TypedArray(Resources resources) {
mResources = resources;
mMetrics = mResources.getDisplayMetrics();
mAssets = mResources.getAssets();
}
複製代碼
這樣就清楚了,typedarray是咱們在靜態方法Typedarray.obtain中獲取的,是從一個Typedarray池中取出來。不難理解,咱們在view中使用typedarray,view會隨着activity的create而create,這樣咱們總不能每次都new一個typedarray出來,因此採用了使用typedarray池來管理。這也就是官方一直強調,用完後要衝水,啊不是,用完後必定要回收。
O了個快速排序K
//做爲Android開發的初學者,若是我有錯誤的地方或者不足的話歡迎你們指正。但願與你們一同進步