文章

04.自定义属性

04.自定义属性

自定义属性

自定义属性步骤

系统自带的 View 可以在 xml 中配置属性,对于写的好的自定义 View 同样可以在 xml 中配置属性,为了使自定义的
View 的属性可以在 xml 中配置,需要以下 4 个步骤:

  1. attrs.xml 通过 <declare-styleable> 为自定义 View 添加属性
  2. 在 xml 中为相应的属性声明属性值(注意 namespace)
  3. 在运行时(一般为构造函数)通过 TypedArray 获取获取属性值
  4. 将获取到的属性值应用到 View

Android 自定义控件之自定义属性及自定义属性定义 style

系统 attrs.xml 路径

D:\Android_sdk\sdk\platforms\android-27\data\res\values\attrs.xml

attrs.xml 定义自定义属性值

attrs.xml 文件定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RatioImageView">
        <attr name="ratio" format="float"/>
    </declare-styleable>
    <declare-styleable name="TaskItemView">
        <attr name="task_item_title" format="string"/>
        <attr name="task_item_titleColor" format="color"/>
        <attr name="task_item_titleTextSize" format="dimension"/>
        <attr name="task_item_desc" format="string"/>
        <attr name="task_item_descColor" format="color"/>
        <attr name="task_item_descTextSize" format="dimension"/>
        <attr name="task_item_descIcon" format="reference"/>
        <attr name="task_item_isDescIcon" format="boolean"/>
        <attr name="task_item_isDesc" format="boolean"/>
        <attr name="task_item_isArrow" format="boolean"/>
        <attr name="task_item_isDivider" format="boolean"/>
    </declare-styleable>
</resources>

获取自定义属性值

Java 代码获取:

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
27
28
29
30
31
private String mTitle;
private String mDesc;
private int mTitleColor;
private int mDescColor;
private boolean isDivider;
private boolean isDesc;
private boolean isArrow;
private boolean isDescIcon;
private float mTextSize;
private float mDescSize;
private int mDescIconResId;
private void init(Context context, AttributeSet attrs) {
    mInflater = LayoutInflater.from(getContext());

    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TaskItemView);
    try {
        mTitle = ta.getString(R.styleable.TaskItemView_task_item_title);
        mDesc = ta.getString(R.styleable.TaskItemView_task_item_desc);
        mTitleColor = ta.getColor(R.styleable.TaskItemView_task_item_titleColor, Color.BLACK);
        mDescColor = ta.getColor(R.styleable.TaskItemView_task_item_descColor, Color.BLACK);
        isDivider = ta.getBoolean(R.styleable.TaskItemView_task_item_isDivider, DEFAULT_DIVIDER_SHOW);
        isDesc = ta.getBoolean(R.styleable.TaskItemView_task_item_isDesc, DEFAULT_DESC_SHOW);
        isArrow = ta.getBoolean(R.styleable.TaskItemView_task_item_isArrow, DEFAULT_ARROW_SHOW);
        isDescIcon = ta.getBoolean(R.styleable.TaskItemView_task_item_isDescIcon, DEFAULT_ARROW_SHOW);
        mTextSize = ta.getDimensionPixelSize(R.styleable.TaskItemView_task_item_titleTextSize, TITLE_TEXT_SIZE_DEFAULT_SP);
        mDescSize = ta.getDimensionPixelSize(R.styleable.TaskItemView_task_item_descTextSize, DESC_TEXT_SIZE_DEFAULT_SP);
        mDescIconResId = ta.getResourceId(R.styleable.TaskItemView_task_item_descIcon, R.drawable.ic_task_item_red_packet);
    } finally {
        ta.recycle();
    }
}

format 可选值

1
2
3
4
5
6
7
8
9
10
string:字符串
reference:引用资源
color颜色
boolean布尔值
dimension尺寸值
float浮点型
integer整型
fraction百分数
enum枚举类型
flag位或运算

string 字符串

代码获取 getString()

reference 引用

代码获取 Drawable getDrawable(@StyleableRes int index)
或者 int getResourceId(@StyleableRes int index, int defValue)

color 颜色值

getColor()

boolean 布尔值

getBoolean()

dimension 尺寸值

getDimension()

float 浮点型

getFloat()

integer 整数值

getInt() 或者 getInteger()

fraction 百分比

enum 枚举

1
2
3
4
5
<attr name="type">
    <enum name="password" value="1" />
    <enum name="checkButton" value="2" />
    <enum name="phone" value="3" />
</attr>

其中,一般属性需要指定 nameformat,枚举属性只需指定 name,然后用 enum 标签指定所有可能属性的 namevalue(注:value 只能为 int 型)
获取值还是通过 getInt()

flag 位

1
2
3
4
5
6
7
8
<attr name="mode">
    <flag name="left_text" value="0x000001"/>
    <flag name="left_image" value="0x000010"/>
    <flag name="center_text" value="0x000100"/>
    <flag name="center_image" value="0x001000"/>
    <flag name="right_text" value="0x010000"/>
    <flag name="right_image" value="0x100000"/>
</attr>

java 代码:

1
int mode = ta.getInt(attr, -1);

AttributeSet 和 TypedArray

AttributeSet

保存的是该 View 声明的所有的属性

TypedArray

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

1
2
int widthDimensionId = attrs.getAttributeResourceValue(0, -1);
Log.e(TAG, "layout_width= "+getResources().getDimension(widthDimensionId));

系统中定义的属性:sdk/platforms/android-xx/data/res/values

declare-styleable

就是帮我们在 R.java 中生成代码

1
2
3
4
5
6
7
8
9
10
11
public static final class attr {
    public static final int testAttr=0x7f0100a9;
}

public static final class styleable {
    public static final int test_android_text = 0;
    public static final int test_testAttr = 1;
    public static final int[] test = {
        0x0101014f, 0x7f0100a9
    };
}
  • 引用 Android 系统帮我们定义好的:
    <attr name="android:text"/>,布局中使用 android:text="haha"
  • 引用已经在 attrs.xml 定义好的 attr,没有写 format
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <attr name="test_attr" format="boolean"/>

    <declare-styleable name="EmptyView">
        <attr name="stringtest" format="string"/>
        <attr name="integertest" format="integer"/>

        <attr name="android:text"/>
        <attr name="test_attr"/>

        <attr name="emptyIcon" format="reference"/>
        <attr name="emptyDescText" format="string"/>
        <attr name="emptyDescTextSize" format="dimension"/>
        <attr name="emptyDescTextColor" format="color"/>
    </declare-styleable>
  • format 定义多个值
1
<attr name="textColor" format="reference|color" />

附:Android 中自定义属性的格式详解

1. reference:参考某一资源 ID

1
2
3
4
5
6
7
8
9
10
(1)属性定义:
        <declare-styleable name = "名称">
               <attr name = "background" format = "reference" />
        </declare-styleable>
(2)属性使用:
         <ImageView
                 android:layout_width = "42dip"
                 android:layout_height = "42dip"
                 android:background = "@drawable/图片ID"
                 />

2. color:颜色值

1
2
3
4
5
6
7
8
9
10
(1)属性定义:
        <declare-styleable name = "名称">
               <attr name = "textColor" format = "color" />
        </declare-styleable>
(2)属性使用:
        <TextView
                 android:layout_width = "42dip"
                 android:layout_height = "42dip"
                 android:textColor = "#00FF00"
                 />

3. boolean:布尔值

1
2
3
4
5
6
7
8
9
10
(1)属性定义:
        <declare-styleable name = "名称">
               <attr name = "focusable" format = "boolean" />
        </declare-styleable>
(2)属性使用:
        <Button
                android:layout_width = "42dip"
                android:layout_height = "42dip"
                android:focusable = "true"
                />

4. dimension:尺寸值

1
2
3
4
5
6
7
8
9
(1)属性定义:
        <declare-styleable name = "名称">
               <attr name = "layout_width" format = "dimension" />
        </declare-styleable>
(2)属性使用:
        <Button
                android:layout_width = "42dip"
                android:layout_height = "42dip"
                />

5. float:浮点值

1
2
3
4
5
6
7
8
9
10
(1)属性定义:
        <declare-styleable name = "AlphaAnimation">
               <attr name = "fromAlpha" format = "float" />
               <attr name = "toAlpha" format = "float" />
        </declare-styleable>
(2)属性使用:
        <alpha
               android:fromAlpha = "1.0"
               android:toAlpha = "0.7"
               />

6. integer:整型值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(1)属性定义:
        <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>
(2)属性使用:
        <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
4
5
6
7
8
9
10
(1)属性定义:
        <declare-styleable name = "MapView">
               <attr name = "apiKey" format = "string" />
        </declare-styleable>
(2)属性使用:
        <com.google.android.maps.MapView
                android:layout_width = "fill_parent"
                android:layout_height = "fill_parent"
                android:apiKey = "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g"
                />

8. fraction:百分数

1
2
3
4
5
6
7
8
9
10
11
(1)属性定义:
        <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>
(2)属性使用:
        <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
7
8
9
10
11
12
13
14
15
(1)属性定义:
        <declare-styleable name="名称">
               <attr name="orientation">
                      <enum name="horizontal" value="0" />
                      <enum name="vertical" value="1" />
               </attr>           
        </declare-styleable>
(2)属性使用:
        <LinearLayout
                xmlns:android = "http://schemas.android.com/apk/res/android"
                android:orientation = "vertical"
                android:layout_width = "fill_parent"
                android:layout_height = "fill_parent"
                >
        </LinearLayout>

10. flag:位或运算

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
 (1)属性定义:
         <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>
 (2)属性使用:
        <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
10
(1)属性定义:
        <declare-styleable name = "名称">
               <attr name = "background" format = "reference|color" />
        </declare-styleable>
(2)属性使用:
         <ImageView
                 android:layout_width = "42dip"
                 android:layout_height = "42dip"
                 android:background = "@drawable/图片ID|#00FF00"
                 />

很多自定义属性模板代码

  • 定义属性:
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
27
<declare-styleable name="CommonToolbar">
    <attr name="toolbar_mode">
        <flag name="comon" value="0x000110"/>
        <flag name="left_text" value="0x000001"/>
        <flag name="left_image" value="0x000010"/>
        <flag name="center_text" value="0x000100"/>
        <flag name="center_image" value="0x001000"/>
        <flag name="right_text" value="0x010000"/>
        <flag name="right_image" value="0x100000"/>
    </attr>
    <attr name="left_titleText" format="string"/>
    <attr name="left_titleColor" format="color"/>
    <attr name="left_titleTextSize" format="dimension"/>
    <attr name="left_titleIcon" format="reference"/>
    <attr name="center_titleText" format="string"/>
    <attr name="center_titleColor" format="color"/>
    <attr name="center_titleTextSize" format="dimension"/>
    <attr name="center_titleIcon" format="reference"/>
    <attr name="right_titleText" format="string"/>
    <attr name="right_titleColor" format="color"/>
    <attr name="right_titleTextSize" format="dimension"/>
    <attr name="right_titleIcon" format="reference"/>
    <attr name="left_padding_left" format="dimension"/>
    <attr name="right_padding_right" format="dimension"/>
    <attr name="left_margin_left" format="dimension"/>
    <attr name="right_margin_right" format="dimension"/>
</declare-styleable>
  • 很多自定义属性获取模板代码:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
private void initAttrs(Context context, AttributeSet attrs) {
    int defaultTextSize = dip2px(getContext(), DEFAULT_TEXT_SIZE); // android 的默认字体大小为12.0sp

    int defaultTextColorPrimary = getTextColorPrimary();
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CommonToolbar);

    try {
        int indexCount = ta.getIndexCount();
        for (int i = 0; i < indexCount; i++) {
            int attr = ta.getIndex(i);
            switch (attr) {
                case R.styleable.CommonToolbar_toolbar_mode:
                    int mode = ta.getInt(attr, -1);
                    switchMode(mode);
                    break;
                case R.styleable.CommonToolbar_left_titleText:
                    String leftTitleText = ta.getString(attr);
                    setText(mTvLeftTitle, leftTitleText);
                    break;
                case R.styleable.CommonToolbar_left_titleIcon:
                    mLeftTitleDrawableResId = ta.getResourceId(attr, DEFAULT_LEFT_ICON_RES);
                    break;
                case R.styleable.CommonToolbar_left_titleColor:
                    mLeftTextColor = ta.getColor(attr, defaultTextColorPrimary);
                    break;
                case R.styleable.CommonToolbar_left_titleTextSize:
                    mLeftTextSize = ta.getDimensionPixelSize(attr, defaultTextSize);
                    break;
                case R.styleable.CommonToolbar_center_titleText:
                    String centerTitleText = ta.getString(attr);
                    setText(mTvCenterTitle, centerTitleText);
                    break;
                case R.styleable.CommonToolbar_center_titleIcon:
                    mCenterTitleDrawableResId = ta.getResourceId(attr, DEFAULT_CENTER_ICON_RES);
                    break;
                case R.styleable.CommonToolbar_center_titleColor:
                    mCenterTextColor = ta.getColor(attr, defaultTextColorPrimary);
                    break;
                case R.styleable.CommonToolbar_center_titleTextSize:
                    mCenterTextSize = ta.getDimensionPixelSize(attr, defaultTextSize);
                    break;
                case R.styleable.CommonToolbar_right_titleText:
                    String rightTitleText = ta.getString(attr);
                    setText(mTvRightTitle, rightTitleText);
                    break;
                case R.styleable.CommonToolbar_right_titleIcon:
                    mRightTitleDrawableResId = ta.getResourceId(attr, DEFAULT_RIGHT_ICON_RES);
                    break;
                case R.styleable.CommonToolbar_right_titleColor:
                    mRightTextColor = ta.getColor(attr, defaultTextColorPrimary);
                    break;
                case R.styleable.CommonToolbar_right_titleTextSize:
                    mRightTextSize = ta.getDimensionPixelSize(attr, defaultTextSize);
                    break;
                case R.styleable.CommonToolbar_left_padding_left:
                    mLeftPaddingleft = ta.getDimensionPixelSize(attr, dip2px(context, DEFAULT_PADDING_DP));
                    break;
                case R.styleable.CommonToolbar_right_padding_right:
                    mRightPaddingRight = ta.getDimensionPixelSize(attr, dip2px(context, DEFAULT_PADDING_DP));
                    break;
                case R.styleable.CommonToolbar_left_margin_left:
                    mLeftMarginLeft = ta.getDimensionPixelSize(attr, dip2px(context, DEFAULT_MAGIN_DP));
                    break;
                case R.styleable.CommonToolbar_right_margin_right:
                    mRightMarginRight = ta.getDimensionPixelSize(attr, dip2px(context, DEFAULT_MAGIN_DP));
                    break;
                default:
                    break;
            }
        }
    } finally {
        ta.recycle();
    }
}

示例

  • kt 代码
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
private fun initAttributes(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {
	context.obtainStyledAttributes(
		attrs, R.styleable.LurePointCouponVerticalView, defStyleAttr, 0
	).run {
		try {
			// 圆角
			mRoundCornerRadius = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_round_corner_radius,
				dp2px(DEFAULT_ROUND_CORNER_DP)
			).toFloat()
			mRoundCornerWidth = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_round_corner_width,
				dp2px(DEFAULT_BORDER_WIDTH_DP)
			).toFloat()
			mRoundCornerColor = getColor(
				R.styleable.LurePointCouponVerticalView_lpc_round_corner_color,
				Color.WHITE
			)
			// 解析渐变色
			val gradientStartColor = getColor(
				R.styleable.LurePointCouponVerticalView_lpc_gradient_start_color,
				mDefaultBgColor
			)
			val gradientMiddleColor = getColor(
				R.styleable.LurePointCouponVerticalView_lpc_gradient_middle_color,
				-1
			)
			val gradientEndColor = getColor(
				R.styleable.LurePointCouponVerticalView_lpc_gradient_end_color,
				-1
			)
			mGradientColors = if (gradientMiddleColor != -1) {
				if (gradientEndColor != -1) {
					intArrayOf(gradientStartColor, gradientMiddleColor, gradientEndColor)
				} else {
					intArrayOf(gradientStartColor, gradientMiddleColor)
				}
			} else {
				intArrayOf(gradientStartColor, gradientStartColor)
			}
			// 解析渐变方向
			mGradientOrientation = Orientation.values()[
				getInt(
					R.styleable.LurePointCouponVerticalView_lpc_gradient_orientation,
					Orientation.VERTICAL.ordinal
				)
			]
			// 解析边框颜色
			mBorderWidth = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_border_width,
				dp2px(DEFAULT_BORDER_WIDTH_DP)
			).toFloat()
			mBorderColor = getColor(
				R.styleable.LurePointCouponVerticalView_lpc_border_color,
				Color.WHITE
			)
			// 挖洞
			mDashEnable =
				getBoolean(R.styleable.LurePointCouponVerticalView_lpc_dash_enable, false)
			mCutRadius = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_cut_radius,
				dp2px(DEFAULT_CUT_RADIUS_DP)
			).toFloat()
			mCutBorderWidth = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_cut_border_width,
				dp2px(DEFAULT_BORDER_WIDTH_DP)
			).toFloat()
			mCutPadding = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_cut_padding,
				dp2px(DEFAULT_CUT_PADDING_DP)
			).toFloat()
			mCutBorderColor = getColor(
				R.styleable.LurePointCouponVerticalView_lpc_cut_border_color,
				Color.parseColor("#FFE2CF")
			)
			// 虚线
			mDashColor = getColor(
				R.styleable.LurePointCouponVerticalView_lpc_dash_color,
				ResourcesCompat.getColor(resources, android.R.color.background_dark, null)
			)
			mDashStrokeWidth = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_dash_stroke_width,
				SUIUtils.dp2px(context, DEFAULT_BORDER_WIDTH_DP)
			)
			mDashLength = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_dash_length,
				SUIUtils.dp2px(context, DEFAULT_DASH_LENGTH_DP)
			)
			mDashSpaceWidth = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_dash_space,
				SUIUtils.dp2px(context, DEFAULT_DASH_STROKE_WIDTH_DP)
			)
			mDashMarginVertical = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_dash_margin_vertical,
				SUIUtils.dp2px(context, DEFAULT_DASH_MARGIN_DP)
			)
			mDashMarginTop = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_dash_margin_top,
				SUIUtils.dp2px(context, mDashMarginVertical.toFloat())
			)
			mDashMarginBottom = getDimensionPixelSize(
				R.styleable.LurePointCouponVerticalView_lpc_dash_margin_bottom,
				SUIUtils.dp2px(context, mDashMarginVertical.toFloat())
			)
			mDashOrientation = getInt(
				R.styleable.LurePointCouponVerticalView_lpc_dash_orientation,
				Orientation.VERTICAL.ordinal
			)
		} finally {
			recycle()
		}
	}
}
  • xml
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
27
28
29
30
31
32
33
34
35
36
37
<declare-styleable name="LurePointCouponVerticalView">
	<!--渐变-->
	<attr name="lpc_gradient_start_color" format="color" />
	<attr name="lpc_gradient_middle_color" format="color" />
	<attr name="lpc_gradient_end_color" format="color" />
	<attr name="lpc_gradient_orientation" format="integer">
		<enum name="horizontal" value="0" />
		<enum name="vertical" value="1" />
	</attr>
	<!--边框-->
	<attr name="lpc_border_color" format="color" />
	<attr name="lpc_border_width" format="dimension" />
	<!--圆角-->
	<attr name="lpc_round_corner_radius" format="dimension" />
	<attr name="lpc_round_corner_width" format="dimension" />
	<attr name="lpc_round_corner_color" format="color" />

	<!--挖洞-->
	<attr name="lpc_cut_radius" format="dimension" />
	<attr name="lpc_cut_border_width" format="dimension" />
	<attr name="lpc_cut_border_color" format="color" />
	<attr name="lpc_cut_padding" format="dimension" />

	<!--虚线-->
	<attr name="lpc_dash_enable" format="boolean" />
	<attr name="lpc_dash_stroke_width" format="dimension" />
	<attr name="lpc_dash_color" format="color" />
	<attr name="lpc_dash_length" format="dimension" />
	<attr name="lpc_dash_space" format="dimension" />
	<attr name="lpc_dash_margin_top" format="dimension" />
	<attr name="lpc_dash_margin_bottom" format="dimension" />
	<attr name="lpc_dash_margin_vertical" format="dimension" />
	<attr name="lpc_dash_orientation" format="integer">
		<enum name="horizontal" value="0" />
		<enum name="vertical" value="1" />
	</attr>
</declare-styleable>

Reference

  • Android 自定义 View 之 自定义 View 属性

比较全面
http://blog.csdn.net/mybeta/article/details/39962235

  • Android 中自定义属性(attrs.xml,TypedArray 的使用)

format 格式介绍比较详细
http://www.cnblogs.com/zhangs1986/p/3243040.html

本文由作者按照 CC BY 4.0 进行授权