写点什么

Android 深入理解 Android 中的自定义属性,资深 Android 面试题

用户头像
Android架构
关注
发布于: 17 小时前

}


}


2.3、布局文件中使用




<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"


xmlns:tools="http://schemas.android.com/tools"


xmlns:zhy="http://schemas.android.com/apk/res/com.example.test"


android:layout_width="match_parent"


android:layout_height="match_parent" >


<com.example.test.MyTextView


android:layout_width="100dp"


android:layout_height="200dp"


zhy:testAttr="520"


zhy:text="helloworld" />


</RelativeLayout>


运行结果为:


MyTextView: text = helloworld , textAttr = 520


应该都不意外吧,注意下,我的 styleable 的 name 写的是 test,所以说这里并不要求一定是自定义 View 的名字。


三、AttributeSet 与 TypedArray


=========================


下面考虑:


构造方法中的有个参数叫做AttributeSet(eg: MyTextView(Context context, AttributeSet attrs) )这个参数看名字就知道包含的是参数的集合,那么我能不能通过它去获取我的自定义属性呢?


首先AttributeSet中的确保存的是该 View 声明的所有的属性,并且外面的确可以通过它去获取(自定义的)属性,怎么做呢??


其实看下AttributeSet的方法就明白了,下面看代码。


public MyTextView(Context context, AttributeSet attrs) {


super(context, attrs);


int count = attrs.getAttributeCount();


for (int i = 0; i < count; i++) {


String attrName = attrs.getAttributeName(i);


String attrVal = attrs.getAttributeValue(i);


Log.e(TAG, "attrName = " + attrName + " , attrVal = " + attrVal);


}


// ==>use typedarray ...


}


输出:


MyTextView(4136): attrName = layout_width , attrVal = 100.0dip


MyTextView(4136): attrName = layout_height , attrVal = 200.0dip


MyTextView(4136): attrName = text , attrVal = helloworld


MyTextView(4136): attrName = testAttr , attrVal = 520


结合上面的布局文件,你发现了什么??


我擦,果然很神奇,真的获得所有的属性,恩,没错,通过 AttributeSet 可以获得布局文件中定义的所有属性的 key 和 value(还有一些方法,自己去尝试),那么是不是说 TypedArray 这个鬼可以抛弃了呢?答案是:NO!。


现在关注下一个问题:TypedArray 是什么鬼?从哪冒出来的,就要我去使用?


我们简单修改下,布局文件中的 MyTextView 的属性。


<com.example.test.MyTextView


android:layout_width="@dimen/dp100"


android:layout_height="@dimen/dp200"


zhy:testAttr="520"


zhy:text="@string/hello_world" />


现在再次运行的结果是:


MyTextView(4692): attrName = layout_width , attrVal = @2131165234


MyTextView(4692): attrName = layout_height , attrVal = @213


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


1165235


MyTextView(4692): attrName = text , attrVal = @2131361809


MyTextView(4692): attrName = testAttr , attrVal = 520


use typedarray


MyTextView(4692): text = Hello world! , textAttr = 520


发现了什么?通过 AttributeSet 获取的值,如果是引用都变成了 @+数字的字符串。你说,这玩意你能看懂么?那么你看看最后一行使用 TypedArray 获取的值,是不是瞬间明白了什么。


TypedArray 其实是用来简化我们的工作的,比如上例,如果布局中的属性的值是引用类型(比如:@dimen/dp100),如果使用 AttributeSet 去获得最终的像素值,那么需要第一步拿到 id,第二步再去解析 id。而 TypedArray 正是帮我们简化了这个过程。


贴一下:如果通过 AttributeSet 获取最终的像素值的过程:


int widthDimensionId = attrs.getAttributeResourceValue(0, -1);


Log.e(TAG, "layout_width= "+getResources().getDimension(widthDimensionId));


ok,现在别人问你 TypedArray 存在的意义,你就可以告诉他了。


四、declare-styleable


===================


我们已经解决了两个问题,接下来,我们看看布局文件,我们有一个属性叫做:zhy:text。?


总所周知,系统提供了一个属性叫做:android:text,那么我觉得直接使用android:text更 nice,这样的话,考虑问题:


如果系统中已经有了语义比较明确的属性,我可以直接使用嘛?


答案是可以的,怎么做呢??


直接在 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"即可。


这里提一下,系统中定义的属性,其实和我们自定义属性的方式类似,你可以在 sdk/platforms/android-xx/data/res/values 该目录下看到系统中定义的属性。然后你可以在系统提供的 View(eg:TextView)的构造方法中发现 TypedArray 获取属性的代码(自己去看一下)。


ok,接下来,我在想,既然 declare-styleable 这个标签的 name 都能随便写,这么随意的话,那么考虑问题:


styleable 的含义是什么?可以不写嘛?我自定义属性,我声明属性就好了,为什么一定要写个 styleable 呢?


其实的确是可以不写的,怎么做呢?


首先删除 declare-styleable 的标签


那么现在的 attrs.xml 为:


<?xml version="1.0" encoding="utf-8"?>


<resources>


<attr name="testAttr" format="integer" />


</resources>


哟西,so 清爽~?


* MyTextView 实现


package com.example.test;


import android.content.Context;


import android.content.res.TypedArray;


import android.util.AttributeSet;


import android.util.Log;


import android.view.View;


public class MyTextView extends View {


private static final String TAG = MyTextView.class.getSimpleName();


private static final int[] mAttr = { android.R.attr.text, R.attr.testAttr };


private static final int ATTR_ANDROID_TEXT = 0;


private static final int ATTR_TESTATTR = 1;


public MyTextView(Context context, AttributeSet attrs) {


super(context, attrs);


// ==>use typedarray


TypedArray ta = context.obtainStyledAttributes(attrs, mAttr);


String text = ta.getString(ATTR_ANDROID_TEXT);


int textAttr = ta.getInteger(ATTR_TESTATTR, -1);


//输出 text = Hello world! , textAttr = 520


Log.e(TAG, "text = " + text + " , textAttr = " + textAttr);


ta.recycle();


}


}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android 深入理解Android中的自定义属性,资深Android面试题