从 View 的四个构造方法说起
![a7bc1020ec5377755f68323a0c364c2a.png](https://img-blog.csdnimg.cn/img_convert/a7bc1020ec5377755f68323a0c364c2a.png)
image
![4d91758721d1557bdd9aba134d35438c.png](https://img-blog.csdnimg.cn/img_convert/4d91758721d1557bdd9aba134d35438c.png)
声明
View 类的四个构造函数
写过自定义 View 的都知道,View 有四个构造函数,一般大家都知道第一个构造方法是简单的在代码中new View 的时候调用的,第二个构造方法使用最广泛,是对应的生成 xml 中定义的 View 的时候调用的。剩下的两个构造方法,大家了解的就比较少了。一般在自定义 View 的时候都会不加思索的按照固定的写法。
那么你有没有想探究一下里面的关系呢?
构造方法 View(Context context)
![9cf2a06d972cf64ac81bc9e4708edd66.png](https://img-blog.csdnimg.cn/img_convert/9cf2a06d972cf64ac81bc9e4708edd66.png)
image
最简单的构造方法,当在代码中创建一个 View 的时候使用。这种构造方法我们一般不会使用。一般都是在 xml 中定义 view ,很少有直接进行 new view 的,这样写法也不符合规范!
构造方法 View(Context context,@Nullable AttributeSet attrs)
![a2b5d52c25f966924c7bb48b44914506.png](https://img-blog.csdnimg.cn/img_convert/a2b5d52c25f966924c7bb48b44914506.png)
image
这个构造方法是我们最常用的,当我们在 xml 中定义了 View 然后在代码中使用这个 View 的时候,这个 View 就是利用这个构造方法生成的。View 的属性值来自 AttributeSet 的值。
构造方法 View(Context context,@Nullable AttributeSet attrs,int defStyleAttr)
![fa5121f7f6af4910c73cf023faf2402d.png](https://img-blog.csdnimg.cn/img_convert/fa5121f7f6af4910c73cf023faf2402d.png)
image
这个构造方法就是提供了默认的 defStyleAttr 用于指定基本的属性。也就是允许 View 有自己基础的风格。例如:一个 Button 类在调用这个构造函数的时候会给 defStyleAttr 赋予一个默认的值 R.attr.buttonStyle 这个值包含了 Button 的一些基本的风格(会在 Theme 中给出),比如:最小宽度,最大宽度等等基础风格。当然这些值我们都可以在 xml 中通过属性直接改变。
构造方法 View(Context context ,@Nullable AttributeSet attrs,int defStyleAttr,int defStyleRes)
![30414f71d48050e5815debf828eea2d7.png](https://img-blog.csdnimg.cn/img_convert/30414f71d48050e5815debf828eea2d7.png)
image
这个构造方法对比构造方法三就多了一个参数 defStyleRes 这个参数的作用就是再提供一个给 View 提供默认属性的手段。defStyleRes 就是把一些我们想要的属性写到一个 Style 里面,然后把这个 style 赋值给 defStyleRes 就可以了。
四个构造函数总结
第一个构造函数:这个构造函数就是在代码中直接 new view 的时候使用,这样出来的 View 默认是没有任何的属性值,需要后面自己手动 set。
第二个构造函数:这个构造函数是在代码中生成对应 xml 中定义的 View 使用的。这个时候在 xml 中定义的属性值会通过 AttributeSet 传递,这样生成的 View 对象是有默认的属性值的。
第三个构造函数:这个构造函数就是相对于第二个构造函数,多提供了一种给 View 添加默认属性的方式,通过 deftStyleAttr 如果没有默认的值,就用 0 。这样做的好处就是,我们可以默认一个 View 的基础风格。比如可以在 defSyleAttr 中设置背景颜色,字体大小等等基础风格,这样我们定义的这个 View 就有了原始风格了,当然如果你在 xml 中又设置了背景颜色,等于改变了原始的风格,是最优先于 xml 中的属性的。
其实我们使用的很多系统 View 都是通过这种方式来,这里用 Button 来举个例子
![d8b5c923e14164508c88a9e50ba2684d.png](https://img-blog.csdnimg.cn/img_convert/d8b5c923e14164508c88a9e50ba2684d.png)
image
可以看到 Button 在使用第三个构造函数的时候,传入了 com.android.internal.R.attr.buttonSyle这个属性,这个属性我们在属性定义文件 attr 中找到,这个属性的出现就是用来定义 Button 的默认风格的。
![ec44f00e1179b28d60b4629157f64785.png](https://img-blog.csdnimg.cn/img_convert/ec44f00e1179b28d60b4629157f64785.png)
image
然后在主题中给 buttonStyle 赋值,找到系统 Theme
![320629ddb66818400510d06aa29b8980.png](https://img-blog.csdnimg.cn/img_convert/320629ddb66818400510d06aa29b8980.png)
image
可以看到在系统的 Theme 中给 buttonSyle 赋值了,指向了 style/Widget.Holo.Light.Button 这个风格就指定了 Button 的默认风格,当然我们在定义主题的时候,可以自己定义 buttonStyle 这个属性的值。
看一下 style/Widget.Holo.Light.Button 的内容
![0501b6298c06460e1896322d0545f6a8.png](https://img-blog.csdnimg.cn/img_convert/0501b6298c06460e1896322d0545f6a8.png)
image
这里定义了 Button 的一些默认的样式。
其他的 View 也都一样,都是这样的一个路子。
第四个构造函数:第四个构造函数相对第三个构造函数就多了一个 defStyleRes ,说白了就是多了一种提供 View 默认属性的一种方式。这种方式更加的简单,直接在代码中传入 R.style.XX 就可以了。如果没有默认值的话就为 0 。这个参数只有 defStyleAttr 为 0 的时候才会生效。
关于 AttributeSet
我们在 xml 布局文件中,定义 View 的时候,会设定这个 View 很多的属性。AttributeSet 就可以看做是这些属性的集合,包含了属性名和属性值。
举例说明:
第一步:定义 CustomTextView
![1da6474a461caf95a3937392b77f3976.png](https://img-blog.csdnimg.cn/img_convert/1da6474a461caf95a3937392b77f3976.png)
image
可以看到,我在第二个构造函数中把 AttributeSet 的 name 和 value 都打印出来了。
第二步:xml 中使用 CustomTextView
![3bce4dd05f7a894231534d1a030c385b.png](https://img-blog.csdnimg.cn/img_convert/3bce4dd05f7a894231534d1a030c385b.png)
image
第三步:运行程序,查看结果
![93b319463d6e373d60a4cfb4c3f22594.png](https://img-blog.csdnimg.cn/img_convert/93b319463d6e373d60a4cfb4c3f22594.png)
image
可以看到 xml 中定义的 5 个属性全部打印出来。因此 AttributeSet 对应的就是 xml 布局文件中定义的属性
给 View 提供样式的方式
- 直接通过 xml 中的属性
- 这种方式是最直接的,体现形式就是直接在布局中设置属性,在 xml 布局文件中使用 style 也属于这种方式
- 通过 deftStyleAttr 设置属性
- 这种方式主要是用来设置默认属性风格的,使用方式见上面 button,主题中设置不同的类型,View的默认风格会发生改变。
- 通过 defStyleRes 设置属性
- 这种方式是直接在代码中指定一个默认的 style,和 Context 的主题没有关系
- 在 Theme 中设置属性
- 这种方式非常不常见,就是把在布局文件中设置的属性,直接放到 Them 中。
如果同时使用这几种方式给 View 设置了属性那么 View 听谁的呢?
xml中直接定义 > xml 中 style 定义 >defStyleAttr > defStyleRes > Theme 中直接定义