Android自定义属性详细剖析(一)

来源:互联网 发布:mac 浏览器 收藏夹 编辑:程序博客网 时间:2024/05/17 01:08

转载请注明出处:
http://blog.csdn.net/qq347198688/article/details/52665975
本文出自【何嘉龙的博客】

1. 引言

对于自定义属性,我相信大家都接触过,使用过。但是可能对自定义属性存有一些疑问,比如说:

  • 为什么要用到自定义属性?

  • 为什么在xml文件中要用到自定义的命名空间?

  • TintTypedArray与TypedArray有什么不同?

  • format有什么用?可以不加么?

让我们带着这些问题,来进行这篇博客的学习。

2. 常见的例子

进行学习的最好方式,就是有例子作为参考,而不是只是单纯给你灌输理论知识,这样只会苦涩难懂,让新手畏惧不前。

  • 在value目录下新建一个attrs.xml文件如下:

这里写图片描述

  • 接着在attrs.xml文件中,写入自定义声明的属性:
<?xml version="1.0" encoding="utf-8"?><resources>   <declare-styleable name="test">       <attr name="text" format="string"/>       <attr name="testAttr" format="integer"/>   </declare-styleable></resources>
  • 自定义一个View类
package com.example.attrtest;import android.content.Context;import android.support.v7.widget.TintTypedArray;import android.util.AttributeSet;import android.util.Log;import android.view.View;/** * Created by dragonhaw on 2016/9/26. */public class MyTextView extends View {    private static final String TAG = MyTextView.class.getSimpleName();    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        TintTypedArray typedArray = TintTypedArray.obtainStyledAttributes(context, attrs, R.styleable.test, defStyleAttr, 0);        String text = typedArray.getString(R.styleable.test_text);        int testAttr = typedArray.getInteger(R.styleable.test_testAttr, -1);        Log.e(TAG, "text = " + text + ", testAttr = " + testAttr);        typedArray.recycle();    }}
  • 在布局文件中使用
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    >    <com.example.attrtest.MyTextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        app:text="Hello World!"        app:testAttr="520"/></LinearLayout>

好了,我们的自定义属性写好了,而且还放在自定义布局中使用了,那这次应该可以看到结果了吧。让我们来运行一下:
这里写图片描述

咦?好像报错了。让我们来看一下这个错误是什么?

这里写图片描述

大概意思就是, 加载我们的这个自定义View出错。我找了很久才找出解决方法,解决方法就是在自定义View里面加入这几行代码:

public MyTextView(Context context) {       this(context, null);   }public MyTextView(Context context, AttributeSet attrs) {       this(context, attrs, 0);   }

至于出错的原因呢?我推断是当我们在自定义布局中写入我们的自定义View时,所用到的构造函数是带有两个参数的。所以,大家为了防止以后出现莫名其妙而又很难找的错误,最好把那几个构造方法都写出来。

好了,我们把错误已经找出来了,那让我们再继续运行一下:
这里写图片描述

控制台已经帮我们把结果打印出来了。再让我们看一下,那个小程序有没有把那些结果显示出来:

这里写图片描述

嗯?怎么什么都没有?哈哈,其实这才是正常的,因为你根本都没有在自定义View里面去调用onMesure(),onDraw方法,具体的请参考我转载的自定义View文章系列。咦?我们好像没有定义test_text、test_testAttr这两个item吧?但是又好像很眼熟。

这里写图片描述

其实,正如你们脑海里想的那样,代码中自定义属性名称就是这样的,”_”前面的是数组名test,后面是自定义属性名。至于declare-styleable 在Android自定义属性详细剖析(二)中剖析。

3. 解决疑问

在通过一个示例之后,再来跟大家一起解决前面提出的问题。

  • 自定义属性的基本流程

我们现在attrs.xml文件中声明我们所需要的自定义属性,然后在布局文件中通过命名空间找到我们的自定义属性,接着再在布局文件中使用,然后java代码中通过obtainStyledAttributes()方法将布局文件中的自定义属性的值给传进来,进行后续操作。基本流程就是这样了。

  • 为什么要使用自定义属性?

自定义属性,可以让我们直接在布局文件中,使用自己定义的属性,来完成需求。使用过开源框架的同学们应该都知道,我们在使用开源框架时,在布局文件中一般都要加上自己的自定义属性,因为这些属性系统没给我们,是我们自己定义的,来完成很多需求的。可能有同学就有疑问了,那为什么我们不直接在代码中完成需求呢?这个问题很好,其实这体现了面向对象的特性——封装性,你要用一个开源框架时,你都不需要去了解代码内部的结构,只需要在自定义布局中加入自定义属性,不是很简单么?

  • 为什么在xml文件中要用到自定义的命名空间?

先让我们来看到自定义命名空间的格式,xmlns:app=”http://schemas.android.com/apk/res-auto”或者xmlns:app=”http://schemas.android.com/apk/res/com.example.attrtest”,这两个其实是一样的,但是我推荐使用第一个,IDE会自动帮你寻找到项目中的所有自定义属性。所以,要用到自定义的命名空间就是为了帮你去找你自定义的属性。

  • TintTypedArray与TypedArray有什么不同?

这里写图片描述
可以看到,官方的解释是,TintTypedArray跟TypedArray提供一样的API,所以这两个随便使用哪一个都一样,不需要纠结。

  • format有什么用?可以不加么?

这里写图片描述
这个是不加后的结果,直接报错。所以format是必须要加的。如果类型都不知道,我们怎么指定自定义属性的值。
format可以理解为类型, fomat的属性自己定义 根据自己的需要来选择string , integer , dimension , reference , color , enum……

reference:参考指定Theme中资源ID。
dimension:尺寸值
float:浮点型
boolean:布尔值
integer:整型
string:字符串
fraction:百分数
flag:位或运算
Color:颜色
enum:枚举

好啦,自定义属性的第一部分算是讲解完了,如果感兴趣的同学,可以接着看Android自定义属性详细剖析(二)。

1 0
原创粉丝点击