自定义控件(继承系统控件,非自绘)
2016-05-17 18:28
190 查看
1.写一个类继承自已有的控件(比如textview),override其中的构造函数:
第一个构造函数一般在代码里new这个自定义控件时使用
第二个构造函数是在layout的xml文件中声明这个控件时,自动调用,attrs里包含了在xml中给这个自定义view设置的所有属性,包括自定义属性和系统属性
第三个构造函数不会自动调用,一般在第二个构造函数手动调用这个构造函数,defStyleAttr是一个自定义属性,在theme文件中利用这个自定义属性给自定义view中的自定义属性设置默认值(详见下面讲解)
第三个构造函数,只有在api21以上才能使用,也不会自动调用,一般在第三个或第二个构造函数手动调用,defStyleRes用于在theme文件中给自定义view中的自定义属性设置默认值(详见下面讲解)
2.在xml中声明这个自定义控件,并设置相关属性
这时候,可以在其构造函数中获取这些定义的系统属性:
obtainStyledAttributes用于在所有属性集合(attrs)中获取我们需要的属性值,第二个参数是一个int数组,里面设置我们需要获取的属性对应的资源id,比如textview的text属性其实是在android的系统资源的属性文件中设置的一个属性
3.使用自定义属性:
首先在res/values底下建立一个attrs.xml文件,指定自定义属性集合的名字,以及里面的属性名和属性格式:
在xml中定义自定义属性的命名空间并设置自定义属性
自定属性的命名空间名字可以随意,值统一为:http://schemas.android.com/apk/res-auto
在代码中获取自定义属性值:
R.styleable.MyTextViewStyle实际上是一个数组,在自动生成的R文件中可以看到:
4.在哪些地方可以给自定义属性赋值,优先级怎么样:
首先,在布局xml文件中可以给自定义属性赋值,如第3点所示
在样式(style)中也可以给自定义属性赋值
在style.xml中加入一个新的style:
注意name直接设置自定义属性名,不要加前缀
在布局文件中声明控件的style为这个style:
获取属性值的代码不变
style中设置的值比布局xml中设置的值优先级低,也就是说如果同时设置,只有布局xml设置的值起作用
还可以在defStyleAttr(参照第三个构造函数)中给自定义属性赋值:
首先在attrs.xml中设置一个自定义属性:
这个属性不要设置到declare-styleable里面,格式为refrence
然后在style.xml中,找到能影响这个自定义属性的theme,在theme中给这个属性设置值,设置的这个值也是一个自定义style,在这个自定义style中,设置自定义属性的值
获取自定义属性值的代码也要改一下:
obtainStyledAttributes中加入两个参数,后面那个暂时不管(设置为0,表示忽略),前面那个传入用于设置值的自定义属性的资源id
通过defStyleAttr设置的值,优先级比前两个低
还可以通过defStyleRes(参照第四个构造函数)给自定义属性赋值:
首先在styles.xml中定义一个style:
在代码中获取自定义属性值:
defStyleAttr设置为0,表示忽略这个设置
defStyleRes的优先级比布局xml和style低,它和defStyleAttr的关系是:仅在defStyleAttr为0或defStyleAttr不为0但Theme中没有为defStyleAttr属性赋值时起作用,否则defStyleRes的设置不起作用
比如既定义了defStyleRes 又指定了defStyleAttr
虽然获取的是attr_one,并且defStyleRes中给attr_one赋值了,但是得到的值还是null
最后,还可以在theme中直接赋值
这种设置的优先级最低,而且如果是字符串,要把设置的值放到string资源里,否则会乱码
5.为什么要在这么多地方都可以设置:
在布局文件中对单个自定义控件属性赋值,这样需要每个控件都写一次
使用style赋值,可以在每个控件中写一句style=xxx就可以了
使用defStyleRes,defStyleAttr,theme赋值,直接写在theme文件中,设置activity或application的theme就可以对里面所有自定义控件属性赋值,相当于设置默认值
public class MyTextView extends TextView { public MyTextView(Context context) { super(context); } public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); } public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } }
第一个构造函数一般在代码里new这个自定义控件时使用
第二个构造函数是在layout的xml文件中声明这个控件时,自动调用,attrs里包含了在xml中给这个自定义view设置的所有属性,包括自定义属性和系统属性
第三个构造函数不会自动调用,一般在第二个构造函数手动调用这个构造函数,defStyleAttr是一个自定义属性,在theme文件中利用这个自定义属性给自定义view中的自定义属性设置默认值(详见下面讲解)
第三个构造函数,只有在api21以上才能使用,也不会自动调用,一般在第三个或第二个构造函数手动调用,defStyleRes用于在theme文件中给自定义view中的自定义属性设置默认值(详见下面讲解)
2.在xml中声明这个自定义控件,并设置相关属性
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.zhouyi.userdefineattrsandstyle.MainActivity"> <com.example.zhouyi.userdefineattrsandstyle.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" /> </RelativeLayout>
这时候,可以在其构造函数中获取这些定义的系统属性:
public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.text}); String strValue = typedArray.getString(0); }
obtainStyledAttributes用于在所有属性集合(attrs)中获取我们需要的属性值,第二个参数是一个int数组,里面设置我们需要获取的属性对应的资源id,比如textview的text属性其实是在android的系统资源的属性文件中设置的一个属性
3.使用自定义属性:
首先在res/values底下建立一个attrs.xml文件,指定自定义属性集合的名字,以及里面的属性名和属性格式:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyTextViewStyle"> <attr name="attr_one" format="string"/> <attr name="attr_two" format="string" /> <attr name="attr_three" format="string" /> <attr name="attr_four" format="string" /> </declare-styleable> </resources>
在xml中定义自定义属性的命名空间并设置自定义属性
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:test = "http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.zhouyi.userdefineattrsandstyle.MainActivity"> <com.example.zhouyi.userdefineattrsandstyle.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" test:attr_one="attr_one from xml" android:text="Hello World!" /> </RelativeLayout>
自定属性的命名空间名字可以随意,值统一为:http://schemas.android.com/apk/res-auto
在代码中获取自定义属性值:
public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextViewStyle); String strValue_one = typedArray.getString(R.styleable.MyTextViewStyle_attr_one); }
R.styleable.MyTextViewStyle实际上是一个数组,在自动生成的R文件中可以看到:
public static final class attr { public static final int attr_one=0x7f010000; public static final int attr_two=0x7f010001; public static final int attr_three=0x7f010002; public static final int attr_four=0x7f010003; }
public static final class styleable { public static final int[] Customize = { 0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003 }; public static final int MyTextView_attr_one = 0; public static final int MyTextView_attr_two = 1; public static final int MyTextView_attr_three = 2; public static final int MyTextView_attr_four = 3; }
4.在哪些地方可以给自定义属性赋值,优先级怎么样:
首先,在布局xml文件中可以给自定义属性赋值,如第3点所示
在样式(style)中也可以给自定义属性赋值
在style.xml中加入一个新的style:
<style name="ThroughStyle"> <item name="attr_one">attr one from style</item> <item name="attr_two">attr two from style</item> </style>
注意name直接设置自定义属性名,不要加前缀
在布局文件中声明控件的style为这个style:
<com.example.zhouyi.userdefineattrsandstyle.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/ThroughStyle" android:text="Hello World!" />
获取属性值的代码不变
style中设置的值比布局xml中设置的值优先级低,也就是说如果同时设置,只有布局xml设置的值起作用
还可以在defStyleAttr(参照第三个构造函数)中给自定义属性赋值:
首先在attrs.xml中设置一个自定义属性:
<resources> <declare-styleable name="MyTextViewStyle"> <attr name="attr_one" format="string"/> <attr name="attr_two" format="string" /> <attr name="attr_three" format="string" /> <attr name="attr_four" format="string" /> </declare-styleable> <attr name="MyTextViewStyleRef" format="reference"/> </resources>
这个属性不要设置到declare-styleable里面,格式为refrence
然后在style.xml中,找到能影响这个自定义属性的theme,在theme中给这个属性设置值,设置的这个值也是一个自定义style,在这个自定义style中,设置自定义属性的值
<!-- 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="MyTextViewStyleRef">@style/MyTextViewStyleRefValue</item> </style> <style name="MyTextViewStyleRefValue"> <item name="attr_one">attr one from theme reference</item> </style>
获取自定义属性值的代码也要改一下:
public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextViewStyle,R.attr.MyTextViewStyleRef,0); String strValue_one = typedArray.getString(R.styleable.MyTextViewStyle_attr_one); }
obtainStyledAttributes中加入两个参数,后面那个暂时不管(设置为0,表示忽略),前面那个传入用于设置值的自定义属性的资源id
通过defStyleAttr设置的值,优先级比前两个低
还可以通过defStyleRes(参照第四个构造函数)给自定义属性赋值:
首先在styles.xml中定义一个style:
<style name="MyTextViewDefaultStyle"> <item name="attr_one">attr one from default theme</item> </style>
在代码中获取自定义属性值:
public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextViewStyle,0,R.style.MyTextViewDefaultStyle); String strValue_one = typedArray.getString(R.styleable.MyTextViewStyle_attr_one); }
defStyleAttr设置为0,表示忽略这个设置
defStyleRes的优先级比布局xml和style低,它和defStyleAttr的关系是:仅在defStyleAttr为0或defStyleAttr不为0但Theme中没有为defStyleAttr属性赋值时起作用,否则defStyleRes的设置不起作用
比如既定义了defStyleRes 又指定了defStyleAttr
<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="MyTextViewStyleRef">@style/MyTextViewStyleRefValue</item>
</style>
<style name="MyTextViewStyleRefValue">
<item name="attr_two">attr one from theme reference</item>
</style>
<style name="MyTextViewDefaultStyle"> <item name="attr_one">attr one from default theme</item> </style>
public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextViewStyle,R.attr.MyTextViewStyleRef,R.style.MyTextViewDefaultStyle); String strValue_one = typedArray.getString(R.styleable.MyTextViewStyle_attr_one); }
虽然获取的是attr_one,并且defStyleRes中给attr_one赋值了,但是得到的值还是null
最后,还可以在theme中直接赋值
<!-- 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="attr_one">@string/app_name</item> </style>
这种设置的优先级最低,而且如果是字符串,要把设置的值放到string资源里,否则会乱码
5.为什么要在这么多地方都可以设置:
在布局文件中对单个自定义控件属性赋值,这样需要每个控件都写一次
使用style赋值,可以在每个控件中写一句style=xxx就可以了
使用defStyleRes,defStyleAttr,theme赋值,直接写在theme文件中,设置activity或application的theme就可以对里面所有自定义控件属性赋值,相当于设置默认值
相关文章推荐
- 自定义圆角控件
- uinty本地图片的读取和剪裁
- 阿里云持续交付平台CRP | 从代码托管,到一键发布,从持续集成,到持续交付,CRP让交付更加简单、可靠、高效
- opengl fbo 纹理 开发步骤
- 一个矩阵中最大的二维矩阵(元素和最大)
- hibernate中HQL语句
- MongoDB的界面操作工具之rockmongo
- 制作子弹痕迹(到shareMaterial)-Unity
- GBDT(MART) 迭代决策树入门教程 | 简介
- 利用AJAX实现WordPress中的文章列表及评论的分页功能
- RabbitMQ (一)第一个hello world
- SCRUM:第一、二天任务实现情况
- CODEVS 1258 关路灯
- Length of Last Word(easy)
- Apache Prefork、Worker和Event三種MPM分析
- Xcode使用-快捷键
- Scrum4.0+5.0
- [转]Unity3D新手引导开发手记
- 使用nohup进入后台,nohup.out内信息显示不及时
- ZigZag Conversion