以前很少注意到的一些问题,在看过一些大神的文章以后有了一些新的认识。真正觉得自己接触到的android只是冰山一角,大神们确实在这些方面已经超越了我太多太多了。所以虚心学习才能百尺竿头,废话不多说。
本文主要讲解的是自定义控件当中的有关自定义属性的问题,以前的做法是:
1.在res/value目录下创建一个xml文件,在resource节点下,声明declare-styleable标签,在标签里面声明item标签,每个item需要声明name跟format属性 每个item就是一个自定义属性。
2.定义完属性就需要在xml里面使用。首先在布局文件的最外层定义命名空间,然后在自定义view里面使用自定义属性。
3.在自定义view中获取xml文件里面使用的自定义属性 TypedArray array = context.obtainStyledAttributes();第一个参数是xml布局传递过来的属性,第二个参数是自定义的的属性文件,这个函数的作用在笔者看来是为了将xml里面设置的属性跟自定义属性匹配存储到array里面。
4.获取自定义属性的value值,并用于操作。array.getInt();array.getString()等等诸如此类。
然而今天看了大神的文章,又学到了一些东西:
1.构造方法方面的问题,以前从来没有注意过这个问题:众所周知自定义view需要重新父类的构造方法,有一个参数、两个参数、三个参数、四个参数的。一个参数的使用场景主要是用在new 自定义view的时候,两个参数的使用场景主要是布局里面使用自定义view的时候。其余两种构造方法都很少用到。
先来说明一个问题:我在自定义一个button的时候,重写了构造方法,但是在使用的时候,出现的并不是button的样式。看完大神的文章,我才知道了这个错误出现在什么地方,原来是我在自定义view的时候,构造方法里面没有使用默认的样式导致的。都知道构造方法的作用是:初始化一些相关内容以及获取自定义属性。之前我都是这么写的。
public MyCustomImageView(Context context) {
this(context, null);
}
public MyCustomImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);//在此处写入要使用的默认样式文件
}
public MyCustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
//解析xml中自定义控件的属性,并将xml里面的属性与自定义属性进行绑定
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyCustomImageView);
原来构造器的写法是有两种方式的:
第一种方式:
public MyCustomImageView(Context context) {
super(context);
init();
}
public MyCustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyCustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
第二种方式:
public MyCustomImageView(Context context) {
this(context, null);
}
public MyCustomImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyCustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
之所以会出现上述所说的自定义出来的view没有父类控件的默认样式的问题,是因为第二种方式更容易把theme里面的默认样式覆盖掉,这个场景下使用第一种方式更安全。如果需要设置defStyleAttr,使用第二种方式会比较好。
2.获取自定义属性的两种方式:
获取自定义的属性都需要将xml里面设置的属性跟自定义属性文件进行匹配。
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyCustomImageView);
这样xml里面的属性值就跟自定义属性文件里面的属性绑定在一起并存储在typedarray里面。
获取方式一:
String name = typedArray.getString();参数为属性id
int i = typedArray.getInt();第一个参数为属性id,第二个参数为默认值
获取方式二:
int count = typedArray.getIndexCount();//获取typedArray里面所有数据的数量
for (int i = 0; i < count; i++) {
//
Log.i("当前的属性是:", typedArray.getIndex(i) + "");
//要获得自定义属性,根据自定义属性获得xml中自定义属性设置的内容
int attr = typedArray.getIndex(i);//获取指定位置的index
switch (attr) {
case R.styleable.MyCustomImageView_src:
//获取xml里面设置的内容
int imageId = typedArray.getResourceId(R.styleable.MyCustomImageView_src, 0);
// int resoourId = typedArray.getInt(R.styleable.MyCustomImageView_src, R.mipmap.ic_launcher); 这样获得的是全路径
imageView.setBackgroundResource(imageId > 0 ? imageId : R.mipmap.ic_launcher);
break;
case R.styleable.MyCustomImageView_text:
//获取xml里面的内容设置到textview
String text = typedArray.getString(R.styleable.MyCustomImageView_text);
int resourceid = typedArray.getResourceId(R.styleable.MyCustomImageView_text, 0);
textView.setText(resourceid > 0 ? typedArray.getResources().getText(resourceid) : typedArray.getString(R.styleable.MyCustomImageView_text));
break;
}
//在xml文件里面如果使用的是引用,可以使用getResourceId();,如果使用的直接是文字或者数字,可以直接使用 typedArray.getString();或者typedArray.getInt()
3.defStyleRes 这个的作用是指定一个默认的style资源的。如果没有在布局文件里面指定自定义属性,就会自动加载该文件下的属性。
defStyleAttr 是一个attr,它引用了一个style文件,并在当前theme下进行设置。指定一个默认的属性样式。可用于切换不同theme,view进行切换不同样式的场景。
大致如下:
1.首先定义一个attr文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomImageView">
<attr name="text" format="string"></attr>
<attr name="src" format="integer"></attr>
<attr name="attrViewStyleRef" format="reference"></attr>//它的作用就是为了在不同theme下切换不同属性内容的
</declare-styleable>
</resources>
2.然后在theme下进行配置
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="attrViewStyleRef">@style/ref</item>//对应自定义属性当中的属性
</style>
<style name="ref">//不同theme下设置不同的内容style
<item name="text">加油</item>
<item name="src">1</item>
</style>
3.在自定义view的构造函数中进行设置
TypedArray typedArray =context.obtainStyledAttributes(attrs,R.styleable.MyCustomImageView,R.attr.attrViewStyleRef,0);