当给的widget不能满足使用的时候就需要自定义。用xml配置view十分方便。如果我们希望通过xml向view中传递参数,就得多写点东西。下面写的例子是对TextView的一个扩展。TextView提供了设置四个方向图片的功能,但是无法设置图片的大小就不太好了。本文实现了一个新的类TextViewPlus,对TextView进行扩展,让其能够在xml中配置图片大小。
改变图片大小不能在xml中做,但是可以在java代码中做。先取得文本周围四个方向的图片Drawable[],然后分别调用drawable.setBounds()设置大小,最后再放回TextView中。然后问题就出在怎么让类读取xml中信息上了。
代码一共分为3部分: 1.main.xml布局文件; 2. TextViewPlus类; 3. attrs.xml文件,用于让系统识别自定义属性。
1. 在目录res/values下创建attrs.xml文件如下:其中name是名称,format是数据类型。系统会自动生成R文件中name的变量。第5~12行写的需要在布局文件中设置的参数。
2. <?xml version="1.0" encoding="UTF-8"?>
3. <resources>
4.
5. <declare-styleable name="TextViewPlus">
6. <attr name="left_height" format="dimension" />
7. <attr name="left_width" format="dimension" />
8. <attr name="right_height" format="dimension" />
9. <attr name="right_width" format="dimension" />
10. <attr name="top_height" format="dimension" />
11. <attr name="top_width" format="dimension" />
12. <attr name="bottom_height" format="dimension" />
13. <attr name="bottom_width" format="dimension" />
14. </declare-styleable>
15.
16. </resources>
2. 类TextViewPlus : TypedArray可看成是一个Map<Integerkey, Object value>。通过遍历key,来获得各个value。而这个key的值是写在R.stylable中的。
1. /**
2. * 添加可以设置drawable大小的功能
3. *
4. * @author Daniel
5. * @version 创建时间: Jul 26, 2012 5:28:59 PM
6. * */
7. public class TextViewPlus extends TextView {
8. // 需要从xml中读取的各个方向图片的宽和高
9. private int leftHeight = -1;
10. private int leftWidth = -1;
11. private int rightHeight = -1;
12. private int rightWidth = -1;
13. private int topHeight = -1;
14. private int topWidth = -1;
15. private int bottomHeight = -1;
16. private int bottomWidth = -1;
17.
18. public TextViewPlus(Context context) {
19. super(context);
20. }
21.
22. public TextViewPlus(Context context, AttributeSet attrs) {
23. super(context, attrs);
24. // super一定要在我们的代码之前配置文件
25. init(context, attrs, 0);
26. }
27.
28. public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {
29. super(context, attrs, defStyle);
30. // super一定要在我们的代码之前配置文件
31. init(context, attrs, defStyle);
32. }
33.
34. /**
35. * 初始化读取参数
36. * */
37. private void init(Context context, AttributeSet attrs, int defStyle) {
38. // TypeArray中含有我们需要使用的参数
39. TypedArray a = context.obtainStyledAttributes(attrs,
40. R.styleable.TextViewPlus, defStyle, 0);
41. if (a != null) {
42. // 获得参数个数
43. int count = a.getIndexCount();
44. int index = 0;
45. // 遍历参数。先将index从TypedArray中读出来,
46. // 得到的这个index对应于attrs.xml中设置的参数名称在R中编译得到的数
47. // 这里会得到各个方向的宽和高
48. for (int i = 0; i < count; i++) {
49. index = a.getIndex(i);
50. switch (index) {
51. case R.styleable.TextViewPlus_bottom_height:
52. bottomHeight = a.getDimensionPixelSize(index, -1);
53. break;
54. case R.styleable.TextViewPlus_bottom_width:
55. bottomWidth = a.getDimensionPixelSize(index, -1);
56. break;
57. case R.styleable.TextViewPlus_left_height:
58. leftHeight = a.getDimensionPixelSize(index, -1);
59. break;
60. case R.styleable.TextViewPlus_left_width:
61. leftWidth = a.getDimensionPixelSize(index, -1);
62. break;
63. case R.styleable.TextViewPlus_right_height:
64. rightHeight = a.getDimensionPixelSize(index, -1);
65. break;
66. case R.styleable.TextViewPlus_right_width:
67. rightWidth = a.getDimensionPixelSize(index, -1);
68. break;
69. case R.styleable.TextViewPlus_top_height:
70. topHeight = a.getDimensionPixelSize(index, -1);
71. break;
72. case R.styleable.TextViewPlus_top_width:
73. topWidth = a.getDimensionPixelSize(index, -1);
74. break;
75. }
76. }
77.
78. // 获取各个方向的图片,按照:左-上-右-下 的顺序存于数组中
79. Drawable[] drawables = getCompoundDrawables();
80. int dir = 0;
81. // 0-left; 1-top; 2-right; 3-bottom;
82. for (Drawable drawable : drawables) {
83. // 设定图片大小
84. setImageSize(drawable, dir++);
85. }
86. // 将图片放回到TextView中
87. setCompoundDrawables(drawables[0], drawables[1], drawables[2],
88. drawables[3]);
89.
90. }
91.
92. }
93.
94. /**
95. * 设定图片的大小
96. * */
97. private void setImageSize(Drawable d, int dir) {
98. if (d == null) {
99. return;
100. }
101.
102. int height = -1;
103. int width = -1;
104. // 根据方向给宽和高赋值
105. switch (dir) {
106. case 0:
107. // left
108. height = leftHeight;
109. width = leftWidth;
110. break;
111. case 1:
112. // top
113. height = topHeight;
114. width = topWidth;
115. break;
116. case 2:
117. // right
118. height = rightHeight;
119. width = rightWidth;
120. break;
121. case 3:
122. // bottom
123. height = bottomHeight;
124. width = bottomWidth;
125. break;
126. }
127. // 如果有某个方向的宽或者高没有设定值,则不去设定图片大小
128. if (width != -1 && height != -1) {
129. d.setBounds(0, 0, width, height);
130. }
131. }
132. }
3. 布局文件:第3行中的“org.daniel.android.tes”是应用程序的包名(AndroidManifest.xml中的package),“myview”为自己定义的命名空间。17~18行就是使用attrs.xml中定义的属性了。3行中的命名空间一定要与17~18行的前缀对应的。
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. xmlns:myview="http://schemas.android.com/apk/res/org.daniel.android.test"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. android:orientation="vertical" >
7.
8. <org.daniel.android.test.TextViewPlus
9. android:layout_width="wrap_content"
10. android:layout_height="wrap_content"
11. android:layout_gravity="center"
12. android:drawableBottom="@drawable/ic_launcher"
13. android:drawableLeft="@drawable/ic_launcher"
14. android:drawableRight="@drawable/ic_launcher"
15. android:drawableTop="@drawable/ic_launcher"
16. android:text="here is a test"
17. myview:left_height="30dp"
18. myview:left_width="30dp" />
19.
20. </LinearLayout>