Android自定义属性分析

一.引言:

在Android开发中,我们常使用的TextView等其它系统提供的控件,它的属性也是系统提供的,我们使用起来也基本够用。然后当我们需要使用自定义控件,常常需要一些自定义的属性。在这一部分内容中,我们需要在attr.xml中添加styleable和item等标签。现在来理清一下具体工作流程:

(a)自定义一个CustomView(extends View )类,告知是继承什么控件
(b)编写values/attrs.xml,在其中编写styleable和item等标签元素
(c)在布局文件中CustomView使用自定义的属性(注意namespace)
(d)在CustomView的构造方法中通过TypedArray获取

关于这个,我有几个问题:

以上步骤是如何奏效的?
1.styleable 的含义是什么?可以不写嘛?我自定义属性,我声明属性就好了,为什么一定要写个styleable呢?
2.如果系统中已经有了语义比较明确的属性,我可以直接使用嘛?
3.构造方法中的有个参数叫做AttributeSet
(eg: MyTextView(Context context, AttributeSet attrs) )这个参数看名字就知道包含的是参数的数组,那么我能不能通过它去获取我的自定义属性呢?
4.TypedArray是什么鬼?从哪冒出来的,就要我去使用?

以上的问题是从鸿洋大神那里看来的,想仔细分析一下。

二、使用方法

在attr中定义属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="popupbtn">
        <!-- 正常状态下的背景 -->
        <attr name="normalBg" format="reference" />
        <!-- 按下状态下的背景 -->
        <attr name="pressBg" format="reference" />
        <!-- 正常状态下的图标 -->
        <attr name="normalIcon" format="reference" />
        <!-- 按下状态下的图标 -->
        <attr name="pressIcon" format="reference" />
        <!-- 按钮的padding -->

    </declare-styleable>
</resources>

在代码中自定义继承:

public class PopupButton extends Button{
        super(context, attrs);
        this.context = context;
         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.popupbtn);

        //如无定义,则返回默认值-1
        normalBg = typedArray.getResourceId(R.styleable.popupbtn_normalBg, -1);
        pressBg = typedArray.getResourceId(R.styleable.popupbtn_pressBg, -1);
        normalIcon = typedArray.getResourceId(R.styleable.popupbtn_normalIcon, -1);
        pressIcon = typedArray.getResourceId(R.styleable.popupbtn_pressIcon, -1);

        typedArray.recycle();
}

在布局文件中引用:

 <com.ui.view.PopupButton
            android:id="@+id/fans_order_time_btn"
            android:layout_width="120dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:layout_centerInParent="true"
            android:text="预约时间"
            android:textColor="@android:color/black"
            android:textSize="15sp"
            android:background="@android:color/transparent"
            popupbtn:normalIcon="@mipmap/arrow_down"
            popupbtn:pressIcon="@mipmap/arrow_up" 
            popupbtn:normalBg="@mipmap/normal_bg"
            popupbtn:pressBg="@mipmap/press_bg"/>

注意下,我的styleable的name写的是popupbtn,所以说这里并不要求一定是自定义View的名字。

三、AttributeSet与TypedArray

下面考虑:

构造方法中的有个参数叫做AttributeSet(eg: MyTextView(Context context, AttributeSet attrs) )这个参数看名字就知道包含的是参数的集合,那么我能不能通过它去获取我的自定义属性呢?
首先AttributeSet中的确保存的是该View声明的所有的属性,并且外面的确可以通过它去获取(自定义的)属性,怎么做呢?
首先让我们去做一个直观的了解:
这里翻看一下TypedArray的源码会发现,TypedArray是不继承任何类(除了Object)的,也就是说,TypedArray相当于一个工具类,通过context.obtainStyledAttributes方法,将AttributeSet和属性的类型传递进去,比如AttributeSet相当于原材料,属性类型相当于图纸,context.obtainStyledAttributes相当于加工厂加工成所对象的属性,封装到TypedArray这个类里。

现在来验证下是不是呢:
在鸿洋的案例中分析了使用和不使用typedArray的区别:
这里是log日志的输出:

>>use AttributeSet only
MyTextView(4692): attrName = layout_width , attrVal = @2131165234
MyTextView(4692): attrName = layout_height , attrVal = @2131165235
MyTextView(4692): attrName = text , attrVal = @2131361809
MyTextView(4692): attrName = testAttr , attrVal = 520
>>use typedarray
MyTextView(4692): text = Hello world! , textAttr = 520

其中属性值都是通过引用来的,比如android:layout_width=”@dimen/dp100”
这时便会出现这种情况,val变成了@一大串数字。这是为什么呢,想必大家通过上面的直观了解也可以猜到了。

直接赋值给AttributeSet是可以的,如果利用AttributeSet通过引用去获得最终的像素值,那么需要第一步拿到id,第二步再去解析id。AttributeSet就只能完成第一步的工作了。而typedArray却能够很好地简化我们的工作,帮助我们去完成整个获取过程,就像工具类一样。

四、declare-styleable

这部分我看得比较久,主要来考虑以下两个问题:

1.如果系统中已经有了语义比较明确的属性,我可以直接使用嘛?
2.styleable 的含义是什么?可以不写嘛?我自定义属性,我声明属性就好了,为什么一定要写个styleable呢?

首先是第一个问题,答案肯定是可以的。
直接在attrs.xml中使用android:text属性。

   <declare-styleable name="test">
        <attr name="android:text" />
        <attr name="testAttr" format="integer" />
    </declare-styleable>

注意,这里我们是使用已经定义好的属性,不需要去添加format属性(注意声明和使用的区别,差别就是有没有format)。
然后在类中这么获取:ta.getString(R.styleable.test_android_text);布局文件中直接android:text=”@string/hello_world”即可。

这里再安利一下format的几种类型:
所有的format类型
reference 引用
color 颜色
boolean 布尔值
dimension 尺寸值
float 浮点值
integer 整型值
string 字符串
enum 枚举值

然后回答第二个问题:
在删除declare-styleable的标签后,我们需要像系统属性那么做:
声明了一个int数组,数组中的元素就是我们想要获取的attr的id。并且我们根据元素的在数组中的位置,定义了一些整形的常量代表其下标,然后通过TypedArray进行获取。

可以发现,这样的系统代码量将会变得很多,styleale的出现系统可以为我们完成很多常量(int[]数组,下标常量)等的编写,简化我们的开发工作(想想如果一堆属性,自己编写常量,你得写成什么样的代码)。那么大家肯定还知道declare-styleable的name属性,一般情况下写的都是我们自定义View的类名。主要为了直观的表达,该declare-styleable的属性,都是该View所用的。

到这里,主要的问题都回答完闭了。鸿洋的博客地址:
http://blog.csdn.net/lmj623565791/article/details/45022631

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值