当我们写一个自定义控件时需要重写其构造方法,比如这样:
//1个参数的构造方法
public BaseLoadingLayout(Context context) {
super(context);
}
//2个参数的构造方法
public BaseLoadingLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
//3个参数的构造方法
public BaseLoadingLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//4个参数的构造方法
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public BaseLoadingLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr,defStyleRes);
}
其中,第四个构造方法(也就是有四个参数的方法)是sdk21之后view和viewGroup才有的。
如果是new一个自定义view的话,会根据参数来进行构造方法的重载。
直接在xml里引用控件时,对LayoutInflater代码分析,发现会调用两个参数的构造方法,所以要想自定义view能在xml里被引用,要重写其两个参数的构造方法。
if (mConstructorArgs[0] == null) {
// Fill in the context if not already within inflation.
mConstructorArgs[0] = mContext;
}
Object[] args = mConstructorArgs;
args[1] = attrs;
final View view = constructor.newInstance(args);
自定义view有时需要自定义属性
1.在value/attrs.xml里新建StyleableRes 也就是declare-styleable 节点,如下:
2.在view构造方法里取出属性值,并根据属性操作view,代码如下:
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressbar, R.attr.DefaultBaseLoadingLayoutViewStyle , R.style.DefaultCustomViewStyle);
radius = typeArray.getDimension(R.styleable.CircleProgressbar_radius, 80);
strokeWidth = typeArray.getDimension(R.styleable.CircleProgressbar_strokeWidth, 10);
ringColor = typeArray.getColor(R.styleable.CircleProgressbar_ringColor, 0xFF0000);
textColor = typeArray.getColor(R.styleable.CircleProgressbar_textColor, 0xFFFFFF);
typeArray.recycle();
}
其中obtainStyledAttributes方法用来得到最终的view的所有属性值,想写好一个自定义view是要考虑如何获取该view的属性,给view添加属性最直接的方式就是写在layout的xml里面,如果xml里面没写属性或者想直接new一个view时,我们就要去theme里面找,看有theme里面有没有定义这个view的属性,如果没有,需要给view设置一个默认的属性值,obtainStyledAttributes方法就是为了完成以上任务的,来看看他的参数有哪些:
public final TypedArray obtainStyledAttributes(AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
return getTheme().obtainStyledAttributes(
set, attrs, defStyleAttr, defStyleRes);
}
AttributeSet set 代表控件写在布局xml里的属性
@StyleableRes int[] attrs :我们想要得到的所有属性,这是我们自己声明的value/attrs.xml里declare-styleable 节点下的属性
@AttrRes int defStyleAttr:下文再表
/@StyleRes int defStyleRes:如果defStyleAttr传的是0,则取defStyleRes里面的style属性
下面我们来讲defStyleAttr
如果set 为null时(set 是从xml里取到的属性值,当我们直接new一个view而不是从xml里inflate时,set为null),就从defStyleAttr里读取属性值,defStyleAttr从名字来看,它带一个attr,说明它是view的一个属性,只是这个属性是用来定义这个view的默认样式的(当set为空时的样式)。那我们要如何使用它呢?很多人都简单粗暴的直接传0进去,传0进去这一个参数将使view失去默认样式,我们可以定义一个默认样式:
第一步,在values/attrs.xml里加上一个自定义view样式的属性
第二步,在values/attrs.xml里定义一个自定义view的默认样式,比如:
第三步,在values/styles.xml里定义一个theme,theme里加上一行对自定义属性,并引用刚刚定义好的默认style
第四步,把我们自定义的theme应用在application或者对于的activity 。
说白了defStyleAttr就是一个view的style属性,该属性可以在theme里被赋值