一. 前言 自定义属性的使用步骤:
在在values目录下创建自定义属性的Xml文件。
在自定义View的构造方法中解析自定义属性的值。
在布局文件中使用自定义属性。
二. 在values目录下创建自定义属性的Xml文件 1. 小例子 例如:attrs_circle.xml
1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.0" encoding="utf-8" ?> <resources> <!--自定义属性集合:CircleView--> <!--在该集合下,设置不同的自定义属性--> <declare-styleable name="CircleView" > <!--在attr标签下设置需要的自定义属性--> <!--此处定义了一个设置图形的颜色:circle_color属性,格式是color,代表颜色--> <attr name="circle_color" format="color" /> </declare-styleable> </resources>
2. 自定义属性的Xml文件细节介绍
declare-styleable 标签的 name 值 没有硬性要求和自定义的类的名称相同,这个名称值使用来在构造方法中解析自定义的属性值的时候用到的。
declare-styleable 标签下可以嵌套一个个 attr标签,每一个 attr标签 都是一个个自定义的属性。需要指明自定属性的名称 name 以及 自定义属性的类型 format。
3. 自定义属性的类型 1 2 3 4 5 6 7 8 9 <-- 1. reference:使用某一资源ID --> <declare-styleable name ="名称" > <attr name ="background" format ="reference" /> </declare-styleable > <ImageView android:layout_width="42dip" android:layout_height="42dip" app:background="@drawable/图片ID" />
1 2 3 4 5 6 7 8 9 <-- 2. color:颜色值 --> <declare-styleable name ="名称" > <attr name ="textColor" format ="color" /> </declare-styleable > <TextView android:layout_width="42dip" android:layout_height="42dip" android:textColor="#00FF00" />
1 2 3 4 5 6 7 8 9 <-- 3. boolean:布尔值 --> <declare-styleable name ="名称" > <attr name ="focusable" format ="boolean" /> </declare-styleable > <Button android:layout_width="42dip" android:layout_height="42dip" android:focusable="true" />
1 2 3 4 5 6 7 8 <-- 4. dimension:尺寸值 --> <declare-styleable name ="名称" > <attr name ="layout_width" format ="dimension" /> </declare-styleable > <Button android:layout_width="42dp" android:layout_height="42dp" />
1 2 3 4 5 6 7 8 9 10 <-- 5. float:浮点值 --> <declare-styleable name ="AlphaAnimation" > <attr name ="fromAlpha" format ="float" /> <attr name ="toAlpha" format ="float" /> </declare-styleable > <alpha android:fromAlpha="1.0" android:toAlpha="0.7" />
1 2 3 4 5 6 7 8 9 10 11 <-- 6. integer:整型值 --> <declare-styleable name ="AnimatedRotateDrawable" > <attr name ="frameDuration" format ="integer" /> <attr name ="framesCount" format ="integer" /> </declare-styleable > <animated-rotate xmlns:android="http://schemas.android.com/apk/res/android" android:frameDuration="100" android:framesCount="12" />
1 2 3 4 5 6 7 <-- 7. string:字符串 --> <declare-styleable name ="MapView" > <attr name ="apiKey" format ="string" /> </declare-styleable > <com.google.android.maps.MapView android:apiKey="0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g" />
1 2 3 4 5 6 7 8 9 10 11 <-- 8. fraction:百分数 --> <declare-styleable name ="RotateDrawable" > <attr name ="pivotX" format ="fraction" /> <attr name ="pivotY" format ="fraction" /> </declare-styleable > <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:pivotX="200%" android:pivotY="300%" />
1 2 3 4 5 6 7 8 9 10 11 12 13 <-- 9. enum:枚举值 --> <declare-styleable name ="名称" > <attr name ="orientation" > <enum name ="horizontal" value ="0" /> <enum name ="vertical" value ="1" /> </attr > </declare-styleable > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" />
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <-- 10. flag:位或运算 --> <declare-styleable name ="名称" > <attr name ="windowSoftInputMode" > <flag name ="stateUnspecified" value ="0" /> <flag name ="stateUnchanged" value ="1" /> <flag name ="stateHidden" value ="2" /> <flag name ="stateAlwaysHidden" value ="3" /> <flag name ="stateVisible" value ="4" /> <flag name ="stateAlwaysVisible" value ="5" /> <flag name ="adjustUnspecified" value ="0x00" /> <flag name ="adjustResize" value ="0x10" /> <flag name ="adjustPan" value ="0x20" /> <flag name ="adjustNothing" value ="0x30" /> </attr > </declare-styleable > 、<activity android:name=".StyleAndThemeActivity" android:label="@string/app_name" android:windowSoftInputMode="stateUnspecified | stateUnchanged | stateHidden" > <intent-filter > <action android:name ="android.intent.action.MAIN" /> <category android:name ="android.intent.category.LAUNCHER" /> </intent-filter > </activity >
1 2 3 4 5 6 7 8 9 <-- 特别注意:属性定义时可以指定多种类型值 --> <declare-styleable name ="名称" > <attr name ="background" format ="reference|color" /> </declare-styleable > <ImageView android:layout_width="42dip" android:layout_height="42dip" android:background="@drawable/图片ID|#00FF00" />
三. 在自定义View的构造方法中解析自定义属性的值 我们需要在View的第二个构造方法中解析数据。
自定义的属性值被封装在attrs中,context调用obtainStyledAttributes方法,传递 attrs 和 R.styleable.XXX参数,就可以得到自定义属性值的集合TypedArray。
使用TypedArray类内定义的获取对应类型属性值的方法,获取属性值。一般情况下,除了传递要获取的属性名,还有给该属性赋一个默认值。
千万要记住,取出属性一定要使用,不然的话是不会起作用的。
使用完之后一定要调用 recycle 方法,释放资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public CircleView (Context context, @Nullable AttributeSet attrs) { super (context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleView); int color = typedArray.getColor(R.styleable.CircleView_circle_color, Color.GRAY); mPaint.setColor(color); typedArray.recycle(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public boolean getBoolean (@StyleableRes int index, boolean defValue) public int getInt (@StyleableRes int index, int defValue) public int getInteger (@StyleableRes int index, int defValue) public float getFloat (@StyleableRes int index, float defValue) public int getColor (@StyleableRes int index, @ColorInt int defValue) public float getDimension (@StyleableRes int index, float defValue) public int getDimensionPixelSize (@StyleableRes int index, int defValue) public int getLayoutDimension (@StyleableRes int index, int defValue) public float getFraction (@StyleableRes int index, int base, int pbase, float defValue) public int getResourceId (@StyleableRes int index, int defValue) public int getThemeAttributeId (@StyleableRes int index, int defValue) public int getSourceResourceId (@StyleableRes int index, @AnyRes int defaultValue)
四. 解析多类型的属性 在自定义控件时有时会支持多种类型format,那么我们要怎么取值呢?
多种类型format取值的模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CompatTextView); TypedValue value = new TypedValue(); boolean has = array.getValue(R.styleable.CompatTextView_ctv_drawableWidth, value);if (has) { if (value.type == TypedValue.TYPE_FLOAT) { } else if (value.type == TypedValue.TYPE_DIMENSION) { } } else { } array.recycle();
参考文章 手把手教你写一个完整的自定义View
自定义属性多种format的取值方法