零
一、Typedarray干什么用的
我们在写界面布局的xml时,经常要设置组件的属性,比如常用的
android:id="@+id/id_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
复制代码
而假如我们需要对自定义的view、viewgroup等等添加自定义的属性呢?就是需要typedarray了。这次我们的例子是给自定义的view添加属性。
二、怎么用Typedarray
1.准备一个自定义的view
code警告
public class ViewWithAttrs extends View {
public ViewWithAttrs(Context context, AttributeSet attrs){
super(context, attrs);
}
}
复制代码
2.准备(新建)一个arrts.xml
<resources>
<declare-styleable name="ViewWithAttrs">
<attr name="paint_color" format="color"/>
</declare-styleable>
</resources>
复制代码
注意第二行的name="ViewWithAttrs",name就是你要添加属性的组件,一定要和view名字相同。
然后就是添加我们想要的属性了,这里我添加了一条属性,属性名是"paint_color",这个是自己定义的,属性类型是:color。
还有其他可选的类型有:
reference 表示引用,参考某一资源ID
string 表示字符串
color 表示颜色值
dimension 表示尺寸值
boolean 表示布尔值
integer 表示整型值
float 表示浮点值
fraction 表示百分数
enum 表示枚举值
flag 表示位运算
3.主角出现:用typedarray获取xml中的属性
通过Contex的obtainStyledAttributes方法创建typedarray,然后用getXXX来获取对应的属性。
show me the code
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中使用了
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawCircle(200,200,50,mPaint);
}
复制代码
4.等等,我们还没设置好属性
在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
结果图:
三、最后一点思考
AttributeSet的问题
小德我在写自定义的View时,刚开始定义了一个类的属性用来保存从AttributeSet获取的typedarray,但是手滑了把获取typedarray写到了onDraw()方法里了,测试的时候后发现没有成功获取到xml中定义的属性,通过debug这才知道在onDraw方法中拿到的值是空的,采用了默认值。但是这是为什么呢?
经过查找到layoutInflater这个类才清楚,大概意思就是AttributeSet并不是每个View都分配一个,而是有类似于缓存一样的机制,大家是共用的(大概可以这么理解),所以到ondraw就有可能获取到了不是我们需要的AttributeSet了。
typedarray回收?不存在的
为什么一定要强调回收呢?这东西又不是占了线程,我就不回收能怎么样?(其实不回收的话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开发的初学者,如果我有错误的地方或者不足的话欢迎大家指正。希望与大家一同进步