Android自定义View构造函数、自定义属性详解
来源:互联网 发布:java bigdecimal取整 编辑:程序博客网 时间:2024/05/21 06:45
1.引言
小菜鸟写博客,因为刚刚开始写,写的感觉很乱,如果你能看下去,表示感谢。身份小菜鸟,这篇文章看了鸿洋大神的博客,还有其他博客自己做的一个小总结。所以有什么错误请多多指正。
2.初始自定义View的构造函数
public MyView(Context context) { super(context); } public MyView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } /** * @description 这个最小API需要21,所以基本不实现这个方法 */ public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); }
根据以上构造函数先将以下几点基本的
- 代码里new一个View的时候,调用的是第一个构造函数
- 在XML布局中调用的时候,调用的是第二个构造函数
- 在XML布局中调用并且有自定义属性也是调用第二个构造函数
总结:说明系统只会调用前两个构造函数,第三个构造函数通常是我们在构造函数中自己调用(比如在第二个构造函数中调用第三个 this(context, attrs, 0)
)。具体如何调用得看你自己的需求
3.CustomView的自定义属性
1.declare-styleable 标签的作用
正常的自定义属性(我都是这样子的。。)
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="MyView"> <attr name="titleText" format="string"/> <attr name="titleTextColor" format="color"/> <attr name="titleTextSize" format="dimension"/> </declare-styleable></resources>
有人说那我不要declare-styleable标签可以不?
答案是当然可以,但是有什么不同呢,那就请看下去
<declare-styleable name="MyView"> <attr name="titleText" format="string" /> <attr name="titleTextColor" format="color" /> <attr name="titleTextSize" format="dimension" /></declare-styleable>调用方法:TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.MyView);自定义属性 <attr name="titleText" format="string"/> <attr name="titleTextColor" format="color"/> <attr name="titleTextSize" format="dimension"/>调用方法:int[] attr=new int[]{R.attr.titleText,R.attr.titleTextColor,R.attr.titleTextSize};TypedArray typedArray = context.obtainStyledAttributes(attrs, attr);
接着往下看
所有resources文件中声明的属性都会在R.attr类中生成对应的成员变量:
我们在attr类中找到我们定义的:
public final class R{ public static final class attr{ public static final int titleText=0x7f01010d; public static final int titleTextColor=0x7f01010e; public static final int titleTextSize=0x7f01010f; }}
但是声明在标签中的属性,系统还会在R.styleable类中生成相关的成员变量:
public static final class styleable{ public static final int[] MyView = { 0x7f01010d, 0x7f01010e, 0x7f01010f }; public static final int MyView_titleText = 0; public static final int MyView_titleTextColor = 1; public static final int MyView_titleTextSize = 2; }
可以看出R.styleable.MyView是一个数组,期中的元素就是他们的值,下面的MyView_titleText等就是它的索引
总结:根据这个例子就很直观的知道了,这个标签就是为我们提供一个属性数组。分组更加的直观。所以推荐使用该标签
2.使用系统定义的属性
根据之前定义的属性,我们在布局里是使用如下
<com.magicsoft.demoone.MyView android:layout_width="match_parent" android:layout_height="match_parent" app:titleText="我我我" app:titleTextColor="@color/colorPrimary" app:titleTextSize="16dp" />
看布局可知我们有一个属性叫做app:titleText="我我我"
但是系统有一个属性叫android:text
。
问题:这在系统中是一个语义比较明确的属性,可以直接使用吗?
答案当然是可以,如下直接在attrs中使用
<declare-styleable name="MyView"> <attr name="android:text"/> <attr name="titleTextColor" format="color"/> <attr name="titleTextSize" format="dimension"/></declare-styleable>
注意,这里我们是使用已经定义好的属性,不需要去添加format属性(注意声明和使用的区别,差别就是有没有format)。
然后在类中这么获取:titleText = typedArray.getString(R.styleable.MyView_android_text);
布局文件中:android:text="我我我"
4.自定义属性详解
obtainStyledAttributes一共有四个参数分别如下
1.AttributeSet
用处:是所有属性的集合
举个例子:我们通过AttributeSet打印出所有的属性
布局文件:
<com.magicsoft.demoone.MyView android:layout_width="match_parent" android:layout_height="match_parent" android:text="我我我我我" app:titleTextSize="16dp" />
代码打印:
int count = attrs.getAttributeCount();for (int i = 0; i < count; i++) {String name = attrs.getAttributeName(i);String value = attrs.getAttributeValue(i);Log.e(TAG, "attrName = " + name + " , attrVal = " + value);}
输出:
MyView: attrName = layout_width , attrVal = -1MyView: attrName = layout_height , attrVal = -1MyView: attrName = text , attrVal = 我我我我我MyView: attrName = titleTextSize , attrVal = 16.0dip
很神奇对不对,所有的属性都有咧。那是不是不用TypedArray了呢。
当然不是咯。 不是都能打印吗? 咋还要用这个什么鬼TypedArray呢。
那接着往下看 我稍微修改下布局
布局:
<com.magicsoft.demoone.MyView android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/me" app:titleTextSize="@dimen/textSize" />
打印代码:
int count = attrs.getAttributeCount(); for (int i = 0; i < count; i++) { String name = attrs.getAttributeName(i); String value = attrs.getAttributeValue(i); Log.e(TAG, "attrName = " + name + " , attrVal = " + value); } TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView,R.attr.myView1,0);titleText = typedArray.getString(R.styleable.MyView_android_text);titleTextSize = typedArray.getDimension(R.styleable.MyView_titleTextSize, 16);Log.e(TAG, "titleText = " + titleText + " , titleTextSize = " + titleTextSize);
输出
MyView: attrName = layout_width , attrVal = -1MyView: attrName = layout_height , attrVal = -1MyView: attrName = text , attrVal = @2131099682MyView: attrName = titleTextSize , attrVal = @2131165282MyView: titleText = 我我我我我 , titleTextSize = 144.0
对比发现了什么?是不是AttributeSet
获取到的值打印出来都是@+一大串数字,再看typedArray打印出来的值
是不是懂了。
TypedArray其实是用来简化我们的工作的,比如上例,如果布局中的属性的值是引用类型(比如:@dimen/textSize),如果使用AttributeSet去获得最终的像素值,那么需要第一步拿到id,第二步再去解析id。而TypedArray正是帮我们简化了这个过程。
2.int[] attrs
这个参数其实前面讲过了,就是你自定义属性的集合,就是在R类中生成的int型数组
3.int defStyleAttr
当在AttributeSet和style属性中都没有找到属性值时,就去Theme的某个属性(即第三个参数)中查看其值是否是style资源,如果是style资源再去这个style资源中查找XML属性值作为替补值。
看的太绕了,那就看以下例子
先看styles.xml,如图所示
<!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> //在AppTheme中,我们设置了defStyleAttrView这个属性的值 <item name="defStyleAttrView">@style/TextViewStyle</item> </style> //颜色设置绿色 <style name="TextViewStyle"> <item name="android:text">我是defStyleAttr</item> <item name="titleTextColor">@color/green</item> <item name="titleTextSize">@dimen/textSize</item> </style>
首先, 我们先声明一个refrence格式的属性, 用于表示style的引用.声明在之前的res/values/attrs_my_view.xml文件里即可:
<attr name="defStyleAttrView" format="reference"/>
接下来看布局文件和MyView代码
<com.magicsoft.demoone.MyView android:layout_width="match_parent" android:layout_height="match_parent" android:text="我不是defStyleAttrView,略略略略" app:titleTextSize="@dimen/textSize" />
布局中改变text内容,不设置颜色。
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView,R.attr.defStyleAttrView,0);
上面的第三个参数已经不是0而是R.attr.defStyleAttrView,但是第四个还是0。接着我们运行看效果
我们发现字是我不是defStyleAttrView,略略略略
,颜色是绿色对不对。为啥呢?
- 文字是这个
我不是defStyleAttrView,略略略略
可以理解吧,因为我直接在XMl里设置了属性。 - 颜色是绿色的,是因为XML和style属性中都没有找到颜色的属性值时,而我们在代码里填写了第三个参数
R.attr.defStyleAttrView
,那么Android会去AppTheme中查找属性为defStyleAttrView的值,他的值是TextViewStyle,由于该值是个style资源,Android就会去该资源中查找titleTextColor的值,TextViewStyle定义了titleTextColor的颜色为绿色,所以MyView最终所使用的titleTextColor的值就是绿色。
总结,看了例子,再看这句话当在AttributeSet和style属性中都没有找到属性值时,就去Theme的某个属性(即第三个参数)中查看其值是否是style资源,如果是style资源再去这个style资源中查找XML属性值作为替补值。
是不是就好理解一点了咧。
4. int defStyleRes
当第三个参数defStyleAttr为0或该属性在theme中找不到时,才会使用第四个参数defStyleRes.如果第三个参数defStyleAttr不为0,该属性在theme中找到,但是所对应的style没有定义任何XML的属性值,那么第四个参数也不会被使用。
defStyleRes本身直接表示一个style资源,这个就很方便
直接看例子咯
先看styles.xml和布局,给他设置个高贵紫。
<style name="defStyleResStyle"> <item name="android:text">我是defStyleResView</item> <item name="titleTextColor">@color/purple</item> <item name="titleTextSize">@dimen/textSize</item> </style>布局 <com.magicsoft.demoone.MyView android:layout_width="match_parent" android:layout_height="match_parent" />
再看MyView,第三个参数是0了,第四个参数设置为R.style.defStyleResStyle
。
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView,0,R.style.defStyleResStyle);
看效果图
看到了吧,显示的是style里定义的文字和颜色吧
这里有个特别注意点:
如果第三个参数defStyleAttr不为0,该属性在theme中找到,但是所对应的style没有定义任何XML的属性值,那么第四个参数也不会被使用。
- Android自定义View构造函数、自定义属性详解
- Android自定义View构造函数详解
- Android自定义View构造函数详解
- android自定义View构造方法以及获取自定义属性详解
- Android自定义View构造函数
- android 自定义 View 构造函数 routine
- android自定义view--构造函数讲解
- Android自定义View 之构造函数
- 自定义View系列一 自定义View的构造函数,自定义属性
- Android自定义View读取XML属性详解
- Android自定义view自定义属性
- Android自定义View-自定义属性
- Android自定义View-自定义属性
- 自定义view-构造方法和自定义属性
- 自定义Android View属性
- Android自定义 view属性
- android 自定义view属性
- android 自定义view属性
- cdq分治(bzoj 1176: [Balkan2007]Mokia && bzoj 2683: 简单题)
- C语言栈的使用
- guzzle/guzzle 日常使用
- 禁止Ctrl+鼠标滚轴浏览器页面缩放
- Java的堆、栈和垃圾回收
- Android自定义View构造函数、自定义属性详解
- 关于retrofit 传值传null的处理(同样适用于okhttp)
- win7自定义共享文件夹名称
- 机器学习相关定义(更新完监督学习)
- MVVM之DataBinding入门
- 13:反向输出一个三位数
- 类的默认构造函数,直接初始化,拷贝构造函数,赋值运算符的执行次数判断
- 分别用Java、Scala、spark-shell开发wordcount程序及测试代码
- 去掉<li>默认的标点