文章已经迁移到简书, 请移步简书进行查看关于Android自定义属性你可能不知道的细节
关于Android自定义属性网上已经有很多大神都已经详细的讲解过了. 关于如何使用自定义属性大家可以参考 鸿洋_大神的这篇文章Android自定义属性Android 深入理解Android中的自定义属性 , 在此小弟再补充一些在自定义属性时候应该注意的一些细节.
- 如何定义可被多个自定义控件使用的属性
- 如何使用Android已经定义好的属性
- 各种类型的属性如何定义(文字样式 , 背景)等.
- 如何读取各种类型的自定义属性
1. 如何定义可被多个自定义控件使用的属性
<declare-styleable name="CustomView">
<attr name="attr1" format="string"/>
</declare-styleable>
假设我们有如上面这段代码 , 然后我们要在另外一个自定义控件中使用名称为” attr1”的自定义属性那么编译器会抛错(错误如下)
Error:Execution failed for task':CustomAttributes:mergeDebugResources'.
> /Users/xxx/WorkSpace/IdeaProjects/MyApplication/CustomAttributes/src/main/res/values/attrs.xml: Error: Found item Attr/attr1 more than one time
那么我们如何定义一个能被多个自定义控件使用的属性呢
我们知道在java类中定义一个被多个实例方法共享的变量—将变量定义在方法体外面,因此我们在自定义属性时也可以使用同样的方法将属性定义在declare-styleable标签之外 , 这样自定义属性就可以被多个自定义控件使用了.
<attr name="attr1" format="string"/>
2.如何使用Android已经定义好的属性
Android系统已经为我们定义好了很多属性名称,所有已
xmlns:android="http://schemas.android.com/apk/res/android"
命名空间,开头的属性都是Android已经定义好的属性 , 在使用的时候只需要直接使用即可, 但是应该注意的是, 如果这个属性在被继承类中已经使用过那么建议不要使用, 如
TextView
的
android:text
属性就是已经被使用的属性, 所以在自定义控件时候如果继承自
TextView
那么这个属性就不应该被使用.
<declare-styleable name="CustomView">
<!--我们可以按下面三行这样来为自定义控件添加,系统已经声明过的属性-->
<attr name="android:divider"/>
<attr name="android:dividerPadding"/>
<attr name="android:showDividers"/>
</declare-styleable>
各种类型的属性如何定义
Android中的属性是如何定义的, 在使用自定义属性的时候我们应该了解Android是如何自定义属性的,.
比如我们定义一个
string
类型的属性
text
那么我们可以使用
<attr name="text" format="string"/>
来定义 .
但是像
textColor
这样的复杂属性 既可以使用
#333333
又可以使用
drawable
类型的值, 这样的属性又改如何定义,
#333333
属于
color
类型 而
drawable
属于
reference
类型 ,这就需要定义个属性使用两种类型的值, 因此我们可以通过
color| reference
来定义如:
<attr name="textColor" format="color|reference"/>
. 其他定义请参考以下代码及注释.
<!--定义文字颜色,这里和系统的TextColor定义相同,注意和背景色读取方式的区别-->
<attr name="CustomTextColor" format="color|reference"/>
<!--定义控件背景色,和系统的Background定义相同,注意和文字颜色读取的区别-->
<attr name="CustomBackground" format="color|reference"/>
4.如何读取各种类型的自定义属性
第一步是获取 declare-styleable
第二步是在获取的集合中取出每个属性值
第三部将读取的属性值应用到自定义
view
自定义属性分有
string,integer,color,reference
等简单类型, 也有
color|reference
等这种复合类型 , 简单类型的读取只需使用
a.getString(R.styleable.CustomView_CustomString)
的方式读取, 复合属性的读取需要按区别对待, 如对于字体和背景同样是
color|reference
类型,但是他们的读取方法也有区别 , 如
textColor
一般使用
ColorStateList
类型
background
一般使用
Drawable
类型. 因此需要使用不同的接口来读取 .
ColorStateList
类型使用
getColorStateList(R.styleable.xxx)
接口,
Drawable
类型使用
getDrawable(R.styleable.xxx)
接口. 具体介绍请参考下面代码.
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
final Resources res = getResources();
// 这里能读取的属性是在<declare-styleable name="CustomView">定义的属性
// 这一行获取 [样式文件]和[控件属性] 里面定义的 <declare-styleable name="CustomView"> 标签中的属性集合
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView, R.attr.CustomStyle, );
// 读取资源文件类型的属性
resource = a.getResourceId(R.styleable.CustomView_CustomResource, );
// 读取color类型的属性(#333333)
color = a.getColor(R.styleable.CustomView_CustomColor, res.getColor(R.color.colorPrimary));
// 读取文字颜色属性(#333333或者selector类型的drawable资源)
textColor = a.getColorStateList(R.styleable.CustomView_CustomTextColor);
// 读取背景(#333333或者drawable类型资源)注意与文字颜色的区别
drawable = a.getDrawable(R.styleable.CustomView_CustomBackground);
// 读取int类型属性
height = a.getInteger(R.styleable.CustomView_CustomHeight, );
// 读取dp类型的属性,读出来的值已经转换为px
width = a.getDimensionPixelSize(R.styleable.CustomView_CustomWidth, );
// 读取字符串类型的属性
text = a.getString(R.styleable.CustomView_CustomString);
// 读取枚举类型的属性
enumValue = a.getInt(R.styleable.CustomView_CustomEnum, );
}
最后附上所有代码
1. attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--给自定义控件定义一个样式,在styles.xml里面可以通过这个样式对控件设置样式-->
<attr name="CustomStyle" format="reference"/>
<!--对应一个引用如drawable,color等-->
<attr name="CustomResource" format="reference"/>
<!--定义一个颜色属性格式为#333333-->
<attr name="CustomColor" format="color"/>
<!--定义文字颜色,这里和系统的TextColor定义相同,注意和背景色读取方式的区别-->
<attr name="CustomTextColor" format="color|reference"/>
<!--定义控件背景色,和系统的Background定义相同,注意和文字颜色读取的区别-->
<attr name="CustomBackground" format="color|reference"/>
<!--定义控件的高度,单位px-->
<attr name="CustomHeight" format="integer"/>
<!--定义控件宽度,单位dp-->
<attr name="CustomWidth" format="dimension"/>
<!--定义一个字符串属性-->
<attr name="CustomString" format="string"/>
<!--定义一个枚举类型属性-->
<attr name="CustomEnum" format="enum">
<enum name="horizontal" value="0"/>
<enum name="vertical" value="1"/>
</attr>
<!--其他属性定义参考以上-->
<!--自定义控件需要用到的属性-->
<declare-styleable name="CustomView">
<!--我们可以按下面三行这样来为自定义控件添加,系统已经声明过的属性-->
<attr name="android:divider"/>
<attr name="android:dividerPadding"/>
<attr name="android:showDividers"/>
<!--在declare-styleable标签中定义的属性不能在另一个declare-styleable标签中再次使用-->
<attr name="OnlyOne" format="boolean"/>
<!--在declare-styleable标签中定义的属性可以被多次使用-->
<attr name="CustomResource"/>
<attr name="CustomColor"/>
<attr name="CustomTextColor"/>
<attr name="CustomBackground"/>
<attr name="CustomHeight"/>
<attr name="CustomWidth"/>
<attr name="CustomString"/>
<attr name="CustomEnum"/>
</declare-styleable>
<declare-styleable name="CustomView1">
<!--在declare-styleable标签中定义的属性不能在另一个declare-styleable标签中再次使用-->
<!--<attr name="OnlyOne" format="boolean"/>-->
<!--在declare-styleable标签中定义的属性可以被多次使用-->
<attr name="CustomColor"/>
</declare-styleable>
</resources>
2. CustomView.java
package com.example.liubin.customattributes;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
public class CustomView extends View {
private final int color;
private final ColorStateList textColor;
private final Drawable drawable;
private final int height;
private final int width;
private final String text;
private final int enumValue;
int resource;
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
final Resources res = getResources();
// 这里能读取的属性是在<declare-styleable name="CustomView">定义的属性
// 这一行获取 [样式文件]和[控件属性] 里面定义的 <declare-styleable name="CustomView"> 标签中的属性集合
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView, R.attr.CustomStyle, );
// 读取资源文件类型的属性
resource = a.getResourceId(R.styleable.CustomView_CustomResource, );
// 读取color类型的属性(#333333)
color = a.getColor(R.styleable.CustomView_CustomColor, res.getColor(R.color.colorPrimary));
// 读取文字颜色属性(#333333或者selector类型的drawable资源)
textColor = a.getColorStateList(R.styleable.CustomView_CustomTextColor);
// 读取背景(#333333或者drawable类型资源)注意与文字颜色的区别
drawable = a.getDrawable(R.styleable.CustomView_CustomBackground);
// 读取int类型属性
height = a.getInteger(R.styleable.CustomView_CustomHeight, );
// 读取dp类型的属性,读出来的值已经转换为px
width = a.getDimensionPixelSize(R.styleable.CustomView_CustomWidth, );
// 读取字符串类型的属性
text = a.getString(R.styleable.CustomView_CustomString);
// 读取枚举类型的属性
enumValue = a.getInt(R.styleable.CustomView_CustomEnum, );
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(color);
Paint paint = new Paint();
paint.setColor(getResources().getColor(R.color.colorPrimary));
canvas.drawText(text, , , paint);
}
}
3. text_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 按下 -->
<item android:color="#333333" android:state_pressed="true"/>
<!-- 获取焦点 -->
<item android:color="#ff0000" android:state_focused="true"/>
<!-- 选中 -->
<item android:color="#ff0000" android:state_selected="true"/>
<!-- 默认 -->
<item android:color="#333333"/>
</selector>
4. activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.liubin.customattributes.MainActivity">
<com.example.liubin.customattributes.CustomView
android:layout_width="300dp"
android:layout_height="300dp"
app:CustomColor="#ff0000"
app:CustomString="我的文字"
app:CustomTextColor="@drawable/text_color"/>
</RelativeLayout>
5. MainActivity.java
package com.example.liubin.customattributes;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}