Android自定义控件的四个构造方法与自定义属性defStyleAttr,defStyleRes详解

当我们写一个自定义控件时需要重写其构造方法,比如这样:

//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里被赋值

你可能感兴趣的:(Android自定义控件的四个构造方法与自定义属性defStyleAttr,defStyleRes详解)