今天我们学习如何自定义TextView组件,让它既能显示文本,又能显示图像,达到“图文并茂”的效果。这种情景在新闻、文章、彩信内容中很常见。下面给出该场景的案例:
一、案例技术要点
1.创建attrs.xml文件用于设置自定义组件的属性、类型和样式。
2.利用android.content.res.TypedArray类将自定义组件装载到程序,以供程序调用。
1. TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.customTextView);
3.布局文件引入自定义组件需要如下设置
自定义组件命名空间:
1. xmlns:custom="http://schemas.android.com/apk/res/com.custom.textview"
自定义组件标签:
1. <com.custom.textview.CustomTextView .../>
4.构造一个HashMap数据结构,用于保存自定义组件的内容类型和值。
key:自定义组件的内容类型(image、text)
value:自定义组件的内容值(imageUrl,CharSequence)
5.利用android.widget.LinearLayout.LayoutParams类用于设置组件的布局参数。这里需要根据显示内容的类型动态地设置组件的布局参数。
二、案例代码陈列
AndroidManifest.xml
1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2. package="com.custom.textview"
3. android:versionCode="1"
4. android:versionName="1.0" >
5.
6. <uses-sdk
7. android:minSdkVersion="8"
8. android:targetSdkVersion="15" />
9.
10. <uses-permission android:name="android.permission.INTERNET"/>
11.
12. <application
13. android:icon="@drawable/ic_launcher"
14. android:label="@string/app_name">
15. <activity
16. android:name=".MainActivity"
17. android:label="@string/app_name" >
18. <intent-filter>
19. <action android:name="android.intent.action.MAIN" />
20.
21. <category android:name="android.intent.category.LAUNCHER" />
22. </intent-filter>
23. </activity>
24. </application>
25.
26. </manifest>
strings.xml
1. <resources>
2. <string name="app_name">自定义TextView实现图文并茂</string>
3. </resources>
自定义TextView组件的属性类型样式文件:attrs.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <resources>
3. <declare-styleable name="customTextView">
4. <attr name="image_width" format="dimension" />
5. <attr name="image_height" format="dimension" />
6. <attr name="text_color" format="color" />
7. <attr name="text_size" format="dimension" />
8. </declare-styleable>
9. </resources>
main.xml
1. <?xml version="1.0" encoding="utf-8" ?>
2. "http://schemas.android.com/apk/res/android"
3. "http://schemas.android.com/apk/res/com.custom.textview"
4. "match_parent"
5. "match_parent"
6. "vertical"
7. "@android:color/white" >
8.
9. <com.custom.textview.CustomTextView
10. "@+id/textView"
11. "match_parent"
12. "wrap_content"
13. "200dp"
14. "50dp" />
15.
16. </LinearLayout>
自定义组件类:CustomTextView.java
1. package com.custom.textview;
2.
3. import java.net.URL;
4. import java.util.ArrayList;
5. import java.util.HashMap;
6.
7. import android.content.Context;
8. import android.content.res.TypedArray;
9. import android.graphics.drawable.Drawable;
10. import android.os.Handler;
11. import android.os.Message;
12. import android.os.SystemClock;
13. import android.text.Html;
14. import android.util.AttributeSet;
15. import android.view.Gravity;
16. import android.widget.ImageView;
17. import android.widget.LinearLayout;
18. import android.widget.TextView;
19.
20. public class CustomTextView extends LinearLayout {
21. private Context context;
22. private TypedArray typedArray;
23. private LayoutParams params;
24.
25. public CustomTextView(Context context) {
26. super(context);
27. }
28.
29. public CustomTextView(Context context, AttributeSet attrs) {
30. super(context, attrs);
31. this.context = context;
32. this.setOrientation(LinearLayout.VERTICAL);
33. // 从attrs.xml中获取自定义属性
34. typedArray = context.obtainStyledAttributes(attrs, R.styleable.customTextView);
35. }
36.
37. public void setText(ArrayList<HashMap<String, String>> data) {
38. for (HashMap<String, String> hashMap : data) {
39. "type");
40. "value");
41. // 如果内容类型是图片
42. if (type.equals("image")) {
43. // 设置图片显示宽高、集中
44. int imageWidth = typedArray.getDimensionPixelOffset(R.styleable.customTextView_image_width, 100);
45. int imageHeight = typedArray.getDimensionPixelOffset(R.styleable.customTextView_image_height, 100);
46. new ImageView(context);
47. new LayoutParams(imageWidth, imageHeight);
48. params.gravity = Gravity.CENTER_HORIZONTAL;
49. imageView.setLayoutParams(params);
50. // 显示默认图片
51. imageView.setImageResource(R.drawable.ic_launcher);
52. // 将ImageView添加到CustomTextView中
53. addView(imageView);
54. // 开启工作线程异步加载图片
55. new DownloadWork(value, imageView).start();
56. else if (type.equals("text")) {
57. int textColor = typedArray.getColor(R.styleable.customTextView_text_color, 0xFF0000FF);
58. float textSize = typedArray.getDimension(R.styleable.customTextView_text_size, 16);
59. new TextView(context);
60. new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
61. textView.setText(Html.fromHtml(value));
62. textView.setTextColor(textColor);
63. textView.setTextSize(textSize);
64. addView(textView);
65. }
66. }
67. }
68.
69. private class DownloadWork extends Thread {
70. private String imageUrl;
71. private ImageView imageView;
72.
73. public DownloadWork(String imageUrl, ImageView imageView) {
74. this.imageUrl = imageUrl;
75. this.imageView = imageView;
76. }
77.
78. @Override
79. public void run() {
80. null;
81. null;
82. int newImageWidth = 0;
83. int newImageHeight = 0;
84. try {
85. new URL(imageUrl);
86. "image");
87. // 对图片进行缩放
88. 3;
89. 3;
90. catch (Exception e) {
91. e.printStackTrace();
92. }
93. 2000);
94.
95. new HashMap<String, Object>();
96. "imageView", imageView);
97. "drawable", drawable);
98. Message msg = handler.obtainMessage();
99. msg.obj = map;
100. msg.arg1 = newImageWidth;
101. msg.arg2 = newImageHeight;
102. handler.sendMessage(msg);
103. }
104. }
105.
106. private Handler handler = new Handler() {
107. public void handleMessage(Message msg) {
108. @SuppressWarnings("unchecked")
109. HashMap<String, Object> map = (HashMap<String, Object>) msg.obj;
110. "imageView");
111. new LayoutParams(msg.arg1, msg.arg2);
112. params.gravity = Gravity.CENTER_HORIZONTAL;
113. imageView.setLayoutParams(params);
114. "drawable");
115. imageView.setImageDrawable(drawable);
116. }
117. };
118. }
MainActivity.java
1. package com.custom.textview;
2.
3. import java.util.ArrayList;
4. import java.util.HashMap;
5.
6. import android.app.Activity;
7. import android.os.Bundle;
8.
9. public class MainActivity extends Activity {
10.
11. private final String text = " <p> 今年浙江卫视凭《中国好声音》一举做大" +
12. ",其巨大的影响力直接波及到了各家卫视“跨年晚会”的战略部署。日前" +
13. ",“跨年晚会”概念的鼻祖湖南卫视率先表示“退出跨年烧钱大战”。" +
14. "但据湖南卫视内部人士透露,即使如此,今年的湖南跨年晚会也将会掂出“跨年季”这个概念" +
15. ",“也就是从12月27日到12月31日,连续五天,我们将相继用《百变大咖秀》、《快乐大本营》" +
16. "、《女人如歌》、《天天向上》的特别节目来连续打造这个”季“的概念,直到12月31日的那场晚会。”</p>";
17.
18. @Override
19. public void onCreate(Bundle savedInstanceState) {
20. super.onCreate(savedInstanceState);
21. setContentView(R.layout.main);
22. // 采集显示内容数据
23. new ArrayList<HashMap<String,String>>();
24. new HashMap<String, String>();
25. "type", "image");
26. "value", "http://www.linuxidc.com/upload/2012_12/121218101020341.png");
27. new HashMap<String, String>();
28. "type", "text");
29. "value", text);
30. new HashMap<String, String>();
31. "type", "image");
32. "value", "http://www.linuxidc.com/upload/2012_12/121218101020341.png");
33. data.add(part1);
34. data.add(part2);
35. data.add(part3);
36.
37. CustomTextView customTextView = (CustomTextView) findViewById(R.id.textView);
38. customTextView.setText(data);
39. }
40. }
三、案例效果展示