12.1 精通自定义 View 之封装控件——自定义属性与自定义 Style

返回自定义 View 目录

12.1.1 示例

1. 自定义 Style 和属性

1)自定义一个类 MyTextView

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyTextView extends AppCompatTextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}

2)新建 res/values/attrs.xml 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<declare-styleable name="MyTextView">
<attr name="header" format="reference"/>
<attr name="headerHeight" format="dimension"/>
<attr name="headerVisibleHeight" format="dimension"/>
<attr name="age">
<flag name="child" value="10"/>
<flag name="young" value="18"/>
<flag name="old" value="60"/>
</attr>
</declare-styleable>
</resources>

  • reference 指的是从 string.xml、drawable.xml、color.xml 等文件中引用过来的值。
  • flag 是自己定义的,类似于 android:gravity=”top”。
  • dimension 指的是从 dimensions.xml 文件中引用过来的值。注意,这里如果是 dp,就会进行像素转换。

注意:declare-styleable 的 name 值对应所定义的类名。自定义属性值可以组合使用。比如 <attr name=”border_color” format=”color | reference”/> 表示既可以自定义 color 值 (比如 #ff00ff),也可以利用 @color/xxx 来引用 colors.xml 中已有的值。

12.1.2 在 XML 中使用自定义的属性

res/layout/act_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:attrstest="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.xxt.xtest.MyTextView
android:layout_width="match_parent"
android:layout_height="match_parent"
attrstest:header="@drawable/head"
attrstest:headerHeight="300dp"
attrstest:headerVisibleHeight="100dp"
attrstest:age="young"/>
</LinearLayout>

下面代码是导入自定义的属性集,使 XML 能识别我们自定义的属性。attrstest 是自定义的,可随意定义为 xxx,对应的访问自定义控件的方式就是 xxx:headerHeight=”300dp”

1
xmlns:attrstest="http://schemas.android.com/apk/res-auto"

12.1.3 在代码中获取自定义属性的值

使用代码获取用户所定义的某个属性的值,主要使用 TypedArray 类,这个类提供了获取某个属性值的所有方法,如下所示。需要注意的是,在使用完以后必须调用 TypedArray 类的 recycle() 函数来释放资源。

1
2
3
4
5
6
7
8
9
typedArray.getInt(int index, float defValue)
typedArray.getDimension(int index, float defValue)
typedArray.getBoolean(int index, float defValue)
typedArray.getColor(int index, float defValue)
typedArray.getString(int index)
typedArray.getDrawable(int index)
typedArray.getResources()
typedArray.recycle()

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyTextView extends AppCompatTextView {
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextView);
float headerHeight = typedArray.getDimension(R.styleable.MyTextView_headerHeight, -1);
int age = typedArray.getInt(R.styleable.MyTextView_age, -1);
Drawable drawable = typedArray.getDrawable(R.styleable.MyTextView_header);
typedArray.recycle();
String text = "headerHeight:" + headerHeight + " age:" + age;
this.setText(text);
}
}

效果如下图所示。

12.1.4 declare-styleable 标签其他属性的用法

1. reference:参考某一资源 ID

属性定义:

1
2
3
<declare-styleable name="名称">
<attr name="background" format="reference"/>
</declare-styleable>

属性使用:

1
2
3
4
<ImageView
android:layout_width="42dip"
android:layout_height="42dip"
android:background="@drawable/图片 ID"/>

2. color:颜色值

属性定义:

1
2
3
<declare-styleable name="名称">
<attr name="textColor" format="color"/>
</declare-styleable>

属性使用:

1
2
3
4
<TextView
android:layout_width="42dip"
android:layout_height="42dip"
android:textColor="#00FF00"/>

3. boolean:布尔值

属性定义:

1
2
3
<declare-styleable name="名称">
<attr name="focusable" format="boolean"/>
</declare-styleable>

属性使用:

1
2
3
4
<Button
android:layout_width="42dip"
android:layout_height="42dip"
android:focusable="true"/>

4. dimension:尺寸值

属性定义:

1
2
3
<declare-styleable name="名称">
<attr name="layout_width" format="dimension"/>
</declare-styleable>

属性使用:

1
2
3
<Button
android:layout_width="42dip"
android:layout_height="42dip"/>

5. float:浮点值

属性定义:

1
2
3
4
<declare-styleable name="AlphaAnimation">
<attr name="fromAlpha" format="float"/>
<attr name="toAlpha" format="float"/>
</declare-styleable>

属性使用:

1
2
3
<Alpha
android:fromAlpha="1.0"
android:toAlpha="0.7"/>

6. integer:整型值

属性定义:

1
2
3
4
5
6
7
8
<declare-styleable name="AnimatedRotateDrawable">
<attr name="visible"/>
<attr name="frameDuration" format="integer"/>
<attr name="framesCount" format="integer"/>
<attr name="pivotX"/>
<attr name="pivotY"/>
<attr name="drawable"/>
</declare-styleable>

属性使用:

1
2
3
4
5
6
7
<animated-rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/图片 ID"
android:pivotX="50%"
android:pivotY="50%"
android:framesCount="12"
android:frameDuration="100"/>

7. string:字符串

属性定义:

1
2
3
<declare-styleable name="MapView">
<attr name="apiKey" format="string"/>
</declare-styleable>

属性使用:

1
2
3
4
<com.google.android.maps.MapView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:apiKey="FJA802hFS01jhFDA9oAFAoFJAFDA9oAFAo"/>

8. fraction:百分数

属性定义:

1
2
3
4
5
6
7
8
<declare-styleable name="RotateDrawable">
<attr name="visible"/>
<attr name="fromDegrees" format="float"/>
<attr name="toDegrees" format="float"/>
<attr name="pivotX" format="fraction"/>
<attr name="pivotY" format="fraction"/>
<attr name="drawable"/>
</declare-styleable>

属性使用:

1
2
3
4
5
6
7
8
9
10
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/动画 ID"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="200%"
android:pivotY="300%"
android:duration="5000"
android:repeatMode="restart"
android:repeatCount="infinite"/>

9. enum:枚举值

属性定义:

1
2
3
4
5
6
<declare-styleable name="名称">
<attr name="orientation">
<enum name="horizontal" value="0"/>
<enum name="vertical" value="1"/>
</attr>
</declare-styleable>

属性使用:

1
2
3
4
5
6
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>

10. flag:位或运算

属性定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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>

属性使用:

1
2
3
4
5
6
7
8
9
<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>
</LinearLayout>

特别注意:属性在定义时可以指定多种类型的值。

1
2
3
<declare-styleable name="名称">
<attr name="background" format="reference|color"/>
</declare-styleable>