自定义View之构造函数学习
2016-09-17 16:39
281 查看
在学习了博客里前辈们的关于自定义View知识,来总结一下我学习自定义View构造函数的收获,以及还有遇到的一些问题。遇到的问题,在以后解决后,会补充。
开始做一件事情,不要求自己一步做到完美,我会慢慢改进学习,去完善。
问题,驱动学习!
一、自定义View构造函数。
一共有四个构造函数,关于有四个参数的构造函数,是在Android API 21 之后才添加的。(AndroidL的新特性)
通过Android source可以看到,第二个,第三个构造函数都是调用了四个参数的构造函数,参数默认补0;
二、添加自定义属性,给要操作的自定义View使用。(这些自定义属性都是针对两个,或者两个以上参数的构造函数使用。)
1、在res目录下,values文件内,新建一个attrs.xml。
通过<declare-styleable>标签内的子标签<attr>,添加View的自定义属性。
<attr name="填写属性名称" format="属性类型">
代码a attr.xml:
关于format的属性类型,参看博客:http://blog.csdn.net/mybeta/article/details/39962235 自定义View属性。
关于<atte name="customize_refernce" format="reference">也可以在<declare-styleable>标签内,或者标签外。移动位置以后,需要clean下代码。任意一条属性都可以。
2、随即,一个问题来,<declare-styleable>标签的作用是什么?
首先不管是否使用<declare-styleable>,系统都会在R.attr中生成他们对应的attribute值。
以下代码都在R.java中的 public static fianl class styleable{} 内部类中。
三、声明自定义属性值(在添加attrs.xml中添加了属性以后。)
1、首先要在根布局中,添加命名空间:
Tip: studio中是/apk/res-auto。eclispe中是全路径名 /apk/自定义View全路径名
2、在xml布局中,创建自定义View布局。不多讲,上代码:
代码b:
3、给自定义属性赋值。
有三种方式赋值方式:
①直接在xml中,给属性直接赋值。cv:attr_string1=@string/custom_view_string
②设置style,并在style中设置属性值,style="@style/customsize_style"
在values文件下styles.xml文件coding。见代码c
③在Application与Activity中指定Theme,可以在Theme中指定在当前Activity或Application中
属性默认值。也是在styles.xml文件coding。
通过attrs.xml 中声明的reference属性,在AppTheme中:
<item name="customize_reference">@style/customize_style_in_theme</item>调用。
问题是,我在打印时,该引用的自定义属性值,没有打印出来,怀疑是parent属性导致。(留坑,待解决)
还有一种方式在Theme中,直接给自定义属性赋值。在打印时,可以看到值。
代码c :styles.xml
四、两个参数的构造函数。 主要看第二个参数:AttributeSet attrs
通过名字可以看出是一个Set集合。
源码给出含义:@param attrs The attributes of the XML tag that is inflating the view.
①关于attrs使用方式,上代码:
由于声明赋值是通过引用,就暴露了其缺点,所以引入TypedArray类,Tag此处用到。因为在<declare-styleable>,
在R.java中生成的是一个数组,见代码b,如果布局中的属性的值是引用类型(比如:@string/custom_view_string),
如果使用AttributeSet去获得最终的像素值,那么需要第一步拿到id,第二步再去解析id。而TypedArray正是帮我们简化了这个过程。
②获取TypedArray 对象 需要通过 TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomViewStudy);方法。
但是obtainStyledAttributes方法最终调用的是getTheme去获取该obtainStyledAttributes系列函数。
public TypedArray obtainStyledAttributes(int[]attrs)
//我主要使用这一个,给自定义属性赋值,使用两个参数的构造函数
public TypedArray obtainStyledAttributes(intresid,int[]attrs)throws
NotFoundException {}
public TypedArray obtainStyledAttributes(AttributeSetset, int[]attrs,intdefStyleAttr,intdefStyleRes){}
说一下其参数含义:
set:属性值的集合
attrs:我们要获取的属性的资源ID的一个数组
defStyleAttr:这个是当前Theme中的一个attribute,是指向style的一个引用,当在layoutxml中和style中都没有为View指定属性时,
会从Theme中这个attribute指向的Style中查找相应的属性值,这就是defStyle的意思,如果没有指定属性值,就用这个值,
所以是默认值,但这个attribute要在Theme中指定,且是指向一个Style的引用,如果这个参数传入0表示不向Theme中搜索默认值
defStyleRes:这个也是指向一个Style的资源ID,但是仅在defStyleAttr为0或defStyleAttr不为0但Theme中没有为defStyleAttr属性赋值时起作用
关于属性值定义的优先级:xml>style>Theme中的默认Sytle>默认Style(通过obtainStyledAttributes的第四个参数指定)>在Theme中直接指定属性值
我在自己的打印日志中,始终看不到通过Theme引用的style方式赋值属性,以及默认的defStyleRes的赋值打印信息。顺序就先牢记,(留坑,待补充)
关于三个参数构造,四个参数构造,我始终在代码中,没有执行走到,就先不写了。自定义View基础先学习到这。
2016-09-28修改start:
关于系统没有调用三个参数,或者四个参数的构造方法,是需要我们自己去在代码中,显示调用三个参数,或者四个参数的构造方法。
2016-09-28修改end。
后记:虽然学习一边,感觉总结有点乱,以后慢慢整理思路。
参考文章: http://blog.csdn.net/lmj623565791/article/details/45022631/ http://www.cnblogs.com/angeldevil/p/3479431.html http://blog.csdn.net/mybeta/article/details/39962235
开始做一件事情,不要求自己一步做到完美,我会慢慢改进学习,去完善。
问题,驱动学习!
一、自定义View构造函数。
一共有四个构造函数,关于有四个参数的构造函数,是在Android API 21 之后才添加的。(AndroidL的新特性)
public class CustonViewComstructorStudy extends View { /**在Java代码中,new一个View时候,通常使用*/ public CustonViewComstructorStudy(Context context) { super(context); } /**在xml中引入一个视图View时,这个View是我们自己定义在xml布局文件当中。 * 官方文档:Constructor that is called when inflating a view from XML.*/ public CustonViewComstructorStudy(Context context, AttributeSet attrs) { super(context, attrs); } /**在打印日志里,始终没有看到程序走第三个构造函数*/ public CustonViewComstructorStudy(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } /**基于Android API 21之后*/ public CustonViewComstructorStudy(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } }
通过Android source可以看到,第二个,第三个构造函数都是调用了四个参数的构造函数,参数默认补0;
二、添加自定义属性,给要操作的自定义View使用。(这些自定义属性都是针对两个,或者两个以上参数的构造函数使用。)
1、在res目录下,values文件内,新建一个attrs.xml。
通过<declare-styleable>标签内的子标签<attr>,添加View的自定义属性。
<attr name="填写属性名称" format="属性类型">
代码a attr.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <!--这里是我们自己写的内容,declare-styleable 的name默认提示与自定义View的类名一致--> <declare-styleable name="CustomViewStudy"> <attr name="attr_string1" format="string"/> <attr name="attr_integer2" format="integer"/> <attr name="attr_boolean3" format="boolean"/> <attr name="attr_float4" format="float"/> <attr name="attr_color5" format="color"/> <attr name="attr_string6" format="string"/> <attr name="android:text"/> <attr name="android:textSize"/> </declare-styleable> <attr name="customize_reference" format="reference"/> </resources>解释说明:
关于format的属性类型,参看博客:http://blog.csdn.net/mybeta/article/details/39962235 自定义View属性。
关于<atte name="customize_refernce" format="reference">也可以在<declare-styleable>标签内,或者标签外。移动位置以后,需要clean下代码。任意一条属性都可以。
2、随即,一个问题来,<declare-styleable>标签的作用是什么?
首先不管是否使用<declare-styleable>,系统都会在R.attr中生成他们对应的attribute值。
public static final int customize_reference=0x7f010000;如果使用了该标签,系统还会在R.styleable中生成相关属性。此处打一个Tag,后序还会用到该属性。
以下代码都在R.java中的 public static fianl class styleable{} 内部类中。
public static final int[] CustomViewStudy = { 0x01010095, 0x0101014f, 0x7f0100a1, 0x7f0100a2, 0x7f0100a3, 0x7f0100a4, 0x7f0100a5, 0x7f0100a6 }; public static final int CustomViewStudy_android_text = 1; public static final int CustomViewStudy_android_textSize = 0; public static final int CustomViewStudy_attr_boolean3 = 4; public static final int CustomViewStudy_attr_color5 = 6; public static final int CustomViewStudy_attr_float4 = 5; public static final int CustomViewStudy_attr_integer2 = 3; public static final int CustomViewStudy_attr_string1 = 2; public static final int CustomViewStudy_attr_string6 = 7;
三、声明自定义属性值(在添加attrs.xml中添加了属性以后。)
1、首先要在根布局中,添加命名空间:
//这是Android系统自带 xmlns:android="http://schemas.android.com/apk/res/android
xmlns:cv="http://schemas.android.com/apk/res-auto"cv:是给自己的自定义属性起的命名空间。放在Android系统自带下边即可。
Tip: studio中是/apk/res-auto。eclispe中是全路径名 /apk/自定义View全路径名
2、在xml布局中,创建自定义View布局。不多讲,上代码:
代码b:
<com.fight.liuhaoqing.a0917customviewconstructor2.CustomViewStudy android:layout_width="wrap_content" android:layout_height="wrap_content" cv:attr_string1="@string/custom_view_string" style="@style/customize_style"/>
3、给自定义属性赋值。
有三种方式赋值方式:
①直接在xml中,给属性直接赋值。cv:attr_string1=@string/custom_view_string
②设置style,并在style中设置属性值,style="@style/customsize_style"
在values文件下styles.xml文件coding。见代码c
③在Application与Activity中指定Theme,可以在Theme中指定在当前Activity或Application中
属性默认值。也是在styles.xml文件coding。
通过attrs.xml 中声明的reference属性,在AppTheme中:
<item name="customize_reference">@style/customize_style_in_theme</item>调用。
问题是,我在打印时,该引用的自定义属性值,没有打印出来,怀疑是parent属性导致。(留坑,待解决)
还有一种方式在Theme中,直接给自定义属性赋值。在打印时,可以看到值。
代码c :styles.xml
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="customize_reference">@style/customize_style_in_theme</item> <item name="attr_string6">string6_in_app_theme</item> </style> <!--自定义View xml中引用的style 属性赋值--> <style name="customize_style"> <item name="attr_string1">你是我的眼</item> <item name="attr_integer2">9527</item> <item name="attr_boolean3">false</item> </style> <!--在AppTheme中引用的style 属性赋值--> <style name="customize_style_in_theme"> <item name="attr_integer2">8888</item> <item name="attr_float4">88.88</item> <item name="attr_color5">#000000</item> </style> <!--在defStyleAttribute不生效时的备用属性赋值--> <style name="customize_style_def_attr_res"> <item name="attr_color5">#ffffff</item> </style> </resources>
四、两个参数的构造函数。 主要看第二个参数:AttributeSet attrs
通过名字可以看出是一个Set集合。
源码给出含义:@param attrs The attributes of the XML tag that is inflating the view.
public View(Context context, AttributeSet attrs) { this(context, attrs, 0); }
①关于attrs使用方式,上代码:
public CustomViewStudy(Context context, AttributeSet attrs) { super(context, attrs); /**此处就是AttributeSet参数的本质上的使用方式。能够取到当前View声明的所有属性。*/ //获取当前 attrs 集合Set大小。 int count = attrs.getAttributeCount(); for (int i = 0; i < count; i++) { String name = attrs.getAttributeName(i);//获取当属性名称 String value = attrs.getAttributeValue(i);//获取当前属性值 Log.w(TAG, "Attribute name :" + name); Log.w(TAG, "Attribute value :" + value); } //通过如下结果可以看出,属性有具体值时可以打印出值,如果是值引用,打印出来的就是一个引用值 //所以,通过TypedArray ta = context.obtainStyledAttribute()方法来取当前View里所有的属性值。 // W/CustomViewStudy: Attribute name :layout_width // W/CustomViewStudy: Attribute value :-2 // W/CustomViewStudy: Attribute name :layout_height // W/CustomViewStudy: Attribute value :-2 // W/CustomViewStudy: Attribute name :attr_string1 // W/CustomViewStudy: Attribute value :@2131099681 }
由于声明赋值是通过引用,就暴露了其缺点,所以引入TypedArray类,Tag此处用到。因为在<declare-styleable>,
在R.java中生成的是一个数组,见代码b,如果布局中的属性的值是引用类型(比如:@string/custom_view_string),
如果使用AttributeSet去获得最终的像素值,那么需要第一步拿到id,第二步再去解析id。而TypedArray正是帮我们简化了这个过程。
②获取TypedArray 对象 需要通过 TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomViewStudy);方法。
但是obtainStyledAttributes方法最终调用的是getTheme去获取该obtainStyledAttributes系列函数。
public TypedArray obtainStyledAttributes(int[]attrs)
//我主要使用这一个,给自定义属性赋值,使用两个参数的构造函数
public TypedArray obtainStyledAttributes(intresid,int[]attrs)throws
NotFoundException {}
public TypedArray obtainStyledAttributes(AttributeSetset, int[]attrs,intdefStyleAttr,intdefStyleRes){}
说一下其参数含义:
set:属性值的集合
attrs:我们要获取的属性的资源ID的一个数组
defStyleAttr:这个是当前Theme中的一个attribute,是指向style的一个引用,当在layoutxml中和style中都没有为View指定属性时,
会从Theme中这个attribute指向的Style中查找相应的属性值,这就是defStyle的意思,如果没有指定属性值,就用这个值,
所以是默认值,但这个attribute要在Theme中指定,且是指向一个Style的引用,如果这个参数传入0表示不向Theme中搜索默认值
defStyleRes:这个也是指向一个Style的资源ID,但是仅在defStyleAttr为0或defStyleAttr不为0但Theme中没有为defStyleAttr属性赋值时起作用
public CustomViewStudy(Context context, AttributeSet attrs) { super(context, attrs); /**此处就是AttributeSet参数的本质上的使用方式。能够取到当前View声明的所有属性。*/ //获取当前 attrs 集合Set大小。 // int count = attrs.getAttributeCount(); // for(int i = 0; i < count; i++){ // String name = attrs.getAttributeName(i);//获取当属性名称 // String value = attrs.getAttributeValue(i);//获取当前属性值 // // Log.w(TAG,"Attribute name :" + name); // Log.w(TAG,"Attribute value :" + value); // } //通过如下结果可以看出,属性有具体值时可以打印出值,如果是值引用,打印出来的就是一个引用值 //所以,通过TypedArray ta = context.obtainStyledAttribute()方法来取当前View里所有的属性值。 // W/CustomViewStudy: Attribute name :layout_width // W/CustomViewStudy: Attribute value :-2 // W/CustomViewStudy: Attribute name :layout_height // W/CustomViewStudy: Attribute value :-2 // W/CustomViewStudy: Attribute name :attr_string1 // W/CustomViewStudy: Attribute value :@2131099681 TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomViewStudy); String attr_str = ta.getString(R.styleable.CustomViewStudy_attr_string1); int attr_int = ta.getInteger(R.styleable.CustomViewStudy_attr_integer2,314); boolean attr_boolean = ta.getBoolean(R.styleable.CustomViewStudy_attr_boolean3,true); float attr_float = ta.getFloat(R.styleable.CustomViewStudy_attr_float4,3.14f); //getColor返回的是一个int值 int attr_color = ta.getColor(R.styleable.CustomViewStudy_attr_color5, Color.parseColor("#5affefff"));//或者格式:Color.BLUE String attr_str6 = ta.getString(R.styleable.CustomViewStudy_attr_string6); Log.e(TAG,"perform 2 params constructor"); Log.e(TAG,"Attribute attr_str:" + attr_str); Log.e(TAG,"Attribute attr_int:" + attr_int); Log.e(TAG,"Attribute attr_boolean:" + attr_boolean); Log.e(TAG,"Attribute attr_float:" + attr_float); Log.e(TAG,"Attribute attr_color:" + attr_color); Log.e(TAG,"Attribute attr_str6:" + attr_str6); ta.recycle();//调用后不会对下次使用造成影响。 }
关于属性值定义的优先级:xml>style>Theme中的默认Sytle>默认Style(通过obtainStyledAttributes的第四个参数指定)>在Theme中直接指定属性值
我在自己的打印日志中,始终看不到通过Theme引用的style方式赋值属性,以及默认的defStyleRes的赋值打印信息。顺序就先牢记,(留坑,待补充)
关于三个参数构造,四个参数构造,我始终在代码中,没有执行走到,就先不写了。自定义View基础先学习到这。
2016-09-28修改start:
关于系统没有调用三个参数,或者四个参数的构造方法,是需要我们自己去在代码中,显示调用三个参数,或者四个参数的构造方法。
2016-09-28修改end。
后记:虽然学习一边,感觉总结有点乱,以后慢慢整理思路。
参考文章: http://blog.csdn.net/lmj623565791/article/details/45022631/ http://www.cnblogs.com/angeldevil/p/3479431.html http://blog.csdn.net/mybeta/article/details/39962235
相关文章推荐
- android 学习笔记(1) ExpandableListActivity 自定义view
- 自定义view,继承view时,构造函数的区别!
- IOS开发学习:MKMapView自定义CalloutView
- Android中自定义样式与View的构造函数中的第三个参数defStyle的意义
- Android文档学习08_自定义view
- APIDemo学习笔记——在XML中使用自定义的View类
- IOS 学习:UITableView使用详解2 自定义的单元格
- 开源组件:DEMO学习-DWinterTabDemo:自定义tab+viewpager
- Apidemo学习 android 自定义View
- Android学习小demo(2)自定义ViewGroup
- Android学习开发 之 自定义view
- ((ios开发学习笔记 十一))自定义TableViewCell 的方式实现自定义TableView(带源码)
- Android学习札记47:TextView显示Html类解析的网页和图片及自定义标签
- Android 学习之--自定义ViewGroup
- Android学习备忘020——android自定义ImageView实现缩放,回弹效果
- Android TextView标点符号换行问题(顺便学习Android自定义View)
- iOS学习之自定义弹出UIPickerView或UIDatePicker(动画效果)
- 在自定义ViewGroup时学习MeasureSpec的使用
- 【Android开发学习】自定义View
- Android学习小demo(3)自定义ViewGroup 利用 scroller 实行屏幕滚动