自定义view获取父类view的系统定义的属性
自定义view是为了实现特别的ui效果而创建的,编写自定义view对于绘制效果的有比较大的自由,但是自定义view应该是在合理利用已有资源的基础上,对于完全无法利用已有资源的情况下,再进行创意;大多数情况,我们只是想对已经存在的ui效果或者机制进行改良,以便更适合我们的app.这个时候,重用系统已经定义了的字段和参数,不仅有利于避免重复工作,也便于让调用者更容易理解这个属性字段的意义,因为他们更熟悉系统已经有的属性。
为了利用起来系统定义了的属性,我们需要在自定义view的构造函数里面获取系统属性。
获取属性的资源id
获取没有被隐藏的资源id
而系统属性的资源引用id往往无法通过“R.java”这个类来获取,因为R.java里面包含的是这个项目我们自己的资源id,而"android.R"这个类只暴露出来了一些参数性质的资源id,比如
图中是android.R的源码,可以看出来,这些属性对应了一个常量,这上面显示的所有常量,都可以是通过"R.android"来调用,比如“android.R.style.Animation”,“android.R.attr.actionBarStyle”。
当把android.R.java的静态内部类的详情收起,会发现anroid.R.java包含了若干个静态内部类,我们并不是直接调用android.R.java的常量,而是调用android.R.java的静态内部类的常量。这些内部类的名字也表明了这个内部类的常量代表的是什么类型的资源id。
查看android.R这个类,可以查看源码。
这些资源对外使用的名称,也可以在android的res文件夹里面查看
在项目的目录下方,“External Libraries”里面包含了所有我们的依赖库,包括android系统库的源码和资源,在res文件夹下,我们可以看到很多资源文件夹
打开values文件夹里面的attrs,我们可以看到很多属性定义和对于这个属性的解释,如果我们的自定义View要使用父类的属性,我们可以在这里查看有哪些属性可以用。
获取隐藏的资源id
然而当我们在对用的"android.R.java"中寻找对应的资源id,会发现根本不包含,所以我们没办法通过android.R.attr.***来访问这些属性,我们需要调用
Resources的方法来帮助我们找到我们要用的资源id
因为这些id虽然不能直接查到,但是我们知道其实它是固定的,因为我们查看源码里面父类的调用,也是通过静态方法来直接调取的。我们可以在androidTest文件夹下编写测试代码,来打印出来我们想要的id的值,然后在编写自定义view的时候直接引用我们找到的值。
我们查看"android.content.res.Resources.java"的源码的这个方法,我们会发现这三个参数的意思。其中defType就是我们在“anroid.R”中看到的各个静态内部类的类名,虽然有些id我们没办法在android.R找到,但是这些资源的类型基本上就是这些,后面参数defPackage是我们所找的资源的包名,比如我们找android.R的资源,我们的包名就是“android”,而被隐藏的系统的资源id,其实也是在"android"这个包里面的,我们只需要也传入“android”就可以找到我们想要的参数id了。
使用获取的资源id
我们通过“android.content.Context"的obtainStyledAttributes来获取TypeArray,然后通过TypeArray来找到我们想要获取的资源的值。其中第二个参数是一个整数数组,一般情况下我们自定义view都会直接通过
“R.styleable.**”来获取我们自己定义的资源,但是当我们想用父类的资源,我们根本没办法直接引用,所以我们需要自己定义一个int[]数组作为参数传进去。这个int[] 其实就是一个View想要获取的资源的Id组成的数组,例如
在RecyclerView里面,
它创建了一个数组名字叫做“NESTED_SCROLLING_ATTRS”,里面包含了一个资源id “16843830”,在注释里面我们看到,它想要引用的这个资源id其实就是“android.R.attr.nestedScrollingEnabled”,也就是说它也无法直接引用这个资源id,所以把id给记了下来。我们可以效仿这种方法,把这个数组作为参数来获取TypeArray。当我们获取了typearray,我们需要获取我们想要的参数值,正常获取参数值的方法,是要传入我们的资源的引用,其实这是一个Index,代表着之前传进去的资源数组的第几个资源,
如图,在android的res文件夹下的attrs.xml里面,R.styleable.View的数组定义的资源id的顺序都是固定的,所以它可以使用“R.styleable.View_fadeScrollbars”来获取参数值,因为R.styleable.View_fadeScrollbars的值就是 它在"R.styleable.View"这个数组中的index
同样,由于我们的int[]是自己直接定义的,我们很清楚哪个属性的Index是多少,比如在RecyclerView中,它定义的“android.R.attr.nestedScrollingEnabled”,在前面有提到的,就是数组的第0个,所以它就使用 a.getBoolean(0,true)来获取
这样我们就可以很清楚父类的属性值被设置成了多少,从而愉快地利用父类定义的属性并且重新实现父类所支持地功能了