该文章我们以自定义View继承TextView为例来讲解
创建自定义View命名MyTextView,并使其继承TextView
1、自定义View时第一个构造函数
// 第一个构造函数主要是在Java代码中声明一个MyTextView时所用 // 类似这种(MyTextView myTextView=new MyTextView(this);) // 不过如果只用第一个构造函数,声明的View并没有任何的参数,基本是个空的View对象
2、自定义View时第二个构造函数
//在XML布局文件中引用时,系统初始化该View时,调用的是第二个构造函数 //参数attrs是我们在xml中配置的参数
前两个构造函数介绍完了,我们说下后两个构造函数
系统默认只会调用前两个构造函数,至于后两个构造函数的调用,通常是我们自己在构造函数中主动调用的,TextView源码亦是如此:
View类的后两个构造函数都是与主题相关的,也就是说,在你自定义View时,如果不需要你的View随着主题变化而变化,有前两个构造函数就OK了,但是如果你想你的View随着主题变化而变化,就需要利用后两个构造函数了。
比如我们定义主题时,用两种方式给自定义View设置主题颜色,如下设置:
xml布局展示:
在主题设置中颜色有两个赋值,为什么最终显示出来的颜色是绿色,而非紫色呢?????
这就涉及到第三个构造函数了,例如源码中TextView,第三个构造函数的调用:
3、自定义View时第三个构造函数
不会自动调用,一般是在第二个构造函数里主动调用
3.1、第三个构造函数中的参数:defStyleAttr 是属性资源, 既然是属性资源,我们首先需要自定义属性
3.2、在主题中对这个自定义属性赋值。(红色)
3.3、构造函数中使用这个自定义属性
4、自定义View时第四个构造函数
不会自动调用,一般是在第三个构造函数里主动调用
第四个构造函数中,defStyleRes这个参数不再是Attr了,而是真正的style。
4.1、定义一个真正的style(橙色)
4.2、在主题未声明属性值时,我们调用第四个构造函数,第四个参数赋值这个橙色style,以这种方式定义出的View,其主题就是这个定义的defStyleRes(想要最终结果显示橙色的前提是:只有在第三个参数defStyleAttr为0,或者主题中没有找到这个defStyleAttr属性的赋值时,才会启用)
由此也可见3种方式设置 textColor的优先级:
defStyleAttr(红色) > defStyleRes(橙色) > theme 中直接定义(绿色)
//注解的意思是告诉Lint工具不需要对这个类进行 AppCompat 兼容性的检查
@SuppressLint("AppCompatCustomView")
public class MyTextView extends TextView {private final String TAG= MyTextView.class.getSimpleName();public MyTextView(Context context) {super(context);Log.d(TAG, "MyTextView: first ");}public MyTextView(Context context, @Nullable AttributeSet attrs) {//super指父类的//super(context, attrs);//this指当前对象,在这里是调用当前对象的第三个构造函数//this(context, attrs, R.attr.textViewColorStyle);this(context, attrs,0);Log.d(TAG, "MyTextView: second ");}public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {// super(context, attrs, defStyleAttr);//调用当前对象的第四个构造函数this(context, attrs,defStyleAttr, R.style.OrangeTextStyle);Log.d(TAG, "MyTextView: three ");}public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);Log.d(TAG, "MyTextView: four ");}}