Android定制组件之图文 (自定义组件图) + TableLayout属性
2013-08-14 23:23
771 查看
传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229
今天我们学习如何自定义TextView组件,让它既能显示文本,又能显示图像,达到“图文并茂”的效果。这种图文混搭的方式常常被用来展现新闻、文章、彩信等内容。下面给出该情景的案例:
1.2利用android.content.res.TypedArray类将自定义组件装载到程序,以供程序调用。
[java]
view plaincopyprint?
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.customTextView);
1.3布局文件引入自定义组件需要如下设置
自定义组件命名空间:
[html]
view plaincopyprint?
xmlns:custom="http://schemas.android.com/apk/res/com.custom.textview"
自定义组件标签:
[html]
view plaincopyprint?
<com.custom.textview.CustomTextView .../>
1.4构造一个HashMap数据结构,用于保存自定义组件的内容类型和值。
key:自定义组件的内容类型(image、text)
value:自定义组件的内容值(imageUrl,CharSequence)
1.5利用android.widget.LinearLayout.LayoutParams类用于设置组件的布局参数。这里需要根据显示内容的类型动态地设置组件的布局参数。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201308/82e6d1325c239d260bdce4b622f7d98e)
2.2AndroidManifest.xml
[html]
view plaincopyprint?
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.custom.textview"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2.3strings.xml
[html]
view plaincopyprint?
<resources>
<string name="app_name">自定义TextView实现图文并茂</string>
</resources>
2.4自定义TextView组件的属性类型样式文件:attrs.xml
[html]
view plaincopyprint?
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="customTextView">
<attr name="image_width" format="dimension" />
<attr name="image_height" format="dimension" />
<attr name="text_color" format="color" />
<attr name="text_size" format="dimension" />
</declare-styleable>
</resources>
2.5main.xml
[java]
view plaincopyprint?
<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.custom.textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/white" >
<com.custom.textview.CustomTextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
custom:image_width="200dp"
custom:image_height="50dp" />
</LinearLayout>
2.6自定义组件类:CustomTextView.java
[java]
view plaincopyprint?
package com.custom.textview;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.Html;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class CustomTextView extends LinearLayout {
private Context context;
private TypedArray typedArray;
private LayoutParams params;
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.setOrientation(LinearLayout.VERTICAL);
// 从attrs.xml中获取自定义属性
typedArray = context.obtainStyledAttributes(attrs, R.styleable.customTextView);
}
public void setText(ArrayList<HashMap<String, String>> data) {
for (HashMap<String, String> hashMap : data) {
String type = hashMap.get("type");
String value = hashMap.get("value");
// 如果内容类型是图片
if (type.equals("image")) {
// 设置图片显示宽高、集中
int imageWidth = typedArray.getDimensionPixelOffset(R.styleable.customTextView_image_width, 100);
int imageHeight = typedArray.getDimensionPixelOffset(R.styleable.customTextView_image_height, 100);
ImageView imageView = new ImageView(context);
params = new LayoutParams(imageWidth, imageHeight);
params.gravity = Gravity.CENTER_HORIZONTAL;
imageView.setLayoutParams(params);
// 显示默认图片
imageView.setImageResource(R.drawable.ic_launcher);
// 将ImageView添加到CustomTextView中
addView(imageView);
// 开启工作线程异步加载图片
new DownloadWork(value, imageView).start();
} else if (type.equals("text")) {
int textColor = typedArray.getColor(R.styleable.customTextView_text_color, 0xFF0000FF);
float textSize = typedArray.getDimension(R.styleable.customTextView_text_size, 16);
TextView textView = new TextView(context);
textView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
textView.setText(Html.fromHtml(value));
textView.setTextColor(textColor);
textView.setTextSize(textSize);
addView(textView);
}
}
}
private class DownloadWork extends Thread {
private String imageUrl;
private ImageView imageView;
public DownloadWork(String imageUrl, ImageView imageView) {
this.imageUrl = imageUrl;
this.imageView = imageView;
}
@Override
public void run() {
URL url = null;
Drawable drawable = null;
int newImageWidth = 0;
int newImageHeight = 0;
try {
url = new URL(imageUrl);
drawable = Drawable.createFromStream(url.openStream(), "image");
// 对图片进行缩放
newImageWidth = drawable.getIntrinsicWidth() / 3;
newImageHeight = drawable.getIntrinsicHeight() / 3;
} catch (Exception e) {
e.printStackTrace();
}
SystemClock.sleep(2000);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("imageView", imageView);
map.put("drawable", drawable);
Message msg = handler.obtainMessage();
msg.obj = map;
msg.arg1 = newImageWidth;
msg.arg2 = newImageHeight;
handler.sendMessage(msg);
}
}
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
@SuppressWarnings("unchecked")
HashMap<String, Object> map = (HashMap<String, Object>) msg.obj;
ImageView imageView = (ImageView) map.get("imageView");
LayoutParams params = new LayoutParams(msg.arg1, msg.arg2);
params.gravity = Gravity.CENTER_HORIZONTAL;
imageView.setLayoutParams(params);
Drawable drawable = (Drawable) map.get("drawable");
imageView.setImageDrawable(drawable);
}
};
}
2.7MainActivity.java
[java]
view plaincopyprint?
package com.custom.textview;
import java.util.ArrayList;
import java.util.HashMap;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
private final String text = " <p> 今年浙江卫视凭《中国好声音》一举做大" +
",其巨大的影响力直接波及到了各家卫视“跨年晚会”的战略部署。日前" +
",“跨年晚会”概念的鼻祖湖南卫视率先表示“退出跨年烧钱大战”。" +
"但据湖南卫视内部人士透露,即使如此,今年的湖南跨年晚会也将会掂出“跨年季”这个概念" +
",“也就是从12月27日到12月31日,连续五天,我们将相继用《百变大咖秀》、《快乐大本营》" +
"、《女人如歌》、《天天向上》的特别节目来连续打造这个”季“的概念,直到12月31日的那场晚会。”</p>";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 采集显示内容数据
ArrayList<HashMap<String, String>> data = new ArrayList<HashMap<String,String>>();
HashMap<String, String> part1 = new HashMap<String, String>();
part1.put("type", "image");
part1.put("value", "http://www.linuxidc.com/upload/2012_12/121218101020341.png");
HashMap<String, String> part2 = new HashMap<String, String>();
part2.put("type", "text");
part2.put("value", text);
HashMap<String, String> part3 = new HashMap<String, String>();
part3.put("type", "image");
part3.put("value", "http://www.linuxidc.com/upload/2012_12/121218101020341.png");
data.add(part1);
data.add(part2);
data.add(part3);
CustomTextView customTextView = (CustomTextView) findViewById(R.id.textView);
customTextView.setText(data);
}
}
![](https://oscdn.geek-share.com/Uploads/Images/Content/201308/53e44c05d75e0daf1e7a6e96b6953509)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201308/d6d280768ba80f218a3241698aa84ec5)
TableLayout经常用到的属性有:
android:collapseColumns:以第0行为序,隐藏指定的列:
android:collapseColumns该属性为空时,效果如下图:
![](http://files.jb51.net/file_images/article/201211/201211071001322.jpg)
把android:collapseColumns=0,2--------------》意思是把第0和第2列去掉,如下图:
![](http://files.jb51.net/file_images/article/201211/201211071001323.jpg)
android:shrinkColumns:以第0行为序,自动延伸指定的列填充可用部分:
当LayoutRow里面的控件还没有布满布局时,shrinkColumns不起作用,如下图:
![](http://files.jb51.net/file_images/article/201211/201211071001324.jpg)
设置了shrinkColumns=0,1,2,布局完全没有改变,因为LayoutRow里面还剩足够的空间。
当LayoutRow布满控件时,如下图:
![](http://files.jb51.net/file_images/article/201211/201211071001325.jpg)
设置设置了shrinkColumns=2,则结果如下图,控件自动向垂直方向填充空间:
![](http://files.jb51.net/file_images/article/201211/201211071001326.jpg)
android:stretchColumns:以第0行为序,尽量把指定的列填充空白部分:
![](http://files.jb51.net/file_images/article/201211/201211071001327.jpg)
设置stretchColumns=1,则结果如下图,第1列被尽量填充(Button02与TextView02同时向右填充,直到TextView03被压挤到最后边)。
今天我们学习如何自定义TextView组件,让它既能显示文本,又能显示图像,达到“图文并茂”的效果。这种图文混搭的方式常常被用来展现新闻、文章、彩信等内容。下面给出该情景的案例:
1案例技术要点
1.1创建attrs.xml文件用于设置自定义组件的属性、类型和样式。1.2利用android.content.res.TypedArray类将自定义组件装载到程序,以供程序调用。
[java]
view plaincopyprint?
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.customTextView);
1.3布局文件引入自定义组件需要如下设置
自定义组件命名空间:
[html]
view plaincopyprint?
xmlns:custom="http://schemas.android.com/apk/res/com.custom.textview"
自定义组件标签:
[html]
view plaincopyprint?
<com.custom.textview.CustomTextView .../>
1.4构造一个HashMap数据结构,用于保存自定义组件的内容类型和值。
key:自定义组件的内容类型(image、text)
value:自定义组件的内容值(imageUrl,CharSequence)
1.5利用android.widget.LinearLayout.LayoutParams类用于设置组件的布局参数。这里需要根据显示内容的类型动态地设置组件的布局参数。
2案例代码陈列
2.1工程包目录2.2AndroidManifest.xml
[html]
view plaincopyprint?
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.custom.textview"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2.3strings.xml
[html]
view plaincopyprint?
<resources>
<string name="app_name">自定义TextView实现图文并茂</string>
</resources>
2.4自定义TextView组件的属性类型样式文件:attrs.xml
[html]
view plaincopyprint?
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="customTextView">
<attr name="image_width" format="dimension" />
<attr name="image_height" format="dimension" />
<attr name="text_color" format="color" />
<attr name="text_size" format="dimension" />
</declare-styleable>
</resources>
2.5main.xml
[java]
view plaincopyprint?
<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.custom.textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/white" >
<com.custom.textview.CustomTextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
custom:image_width="200dp"
custom:image_height="50dp" />
</LinearLayout>
2.6自定义组件类:CustomTextView.java
[java]
view plaincopyprint?
package com.custom.textview;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.Html;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class CustomTextView extends LinearLayout {
private Context context;
private TypedArray typedArray;
private LayoutParams params;
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.setOrientation(LinearLayout.VERTICAL);
// 从attrs.xml中获取自定义属性
typedArray = context.obtainStyledAttributes(attrs, R.styleable.customTextView);
}
public void setText(ArrayList<HashMap<String, String>> data) {
for (HashMap<String, String> hashMap : data) {
String type = hashMap.get("type");
String value = hashMap.get("value");
// 如果内容类型是图片
if (type.equals("image")) {
// 设置图片显示宽高、集中
int imageWidth = typedArray.getDimensionPixelOffset(R.styleable.customTextView_image_width, 100);
int imageHeight = typedArray.getDimensionPixelOffset(R.styleable.customTextView_image_height, 100);
ImageView imageView = new ImageView(context);
params = new LayoutParams(imageWidth, imageHeight);
params.gravity = Gravity.CENTER_HORIZONTAL;
imageView.setLayoutParams(params);
// 显示默认图片
imageView.setImageResource(R.drawable.ic_launcher);
// 将ImageView添加到CustomTextView中
addView(imageView);
// 开启工作线程异步加载图片
new DownloadWork(value, imageView).start();
} else if (type.equals("text")) {
int textColor = typedArray.getColor(R.styleable.customTextView_text_color, 0xFF0000FF);
float textSize = typedArray.getDimension(R.styleable.customTextView_text_size, 16);
TextView textView = new TextView(context);
textView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
textView.setText(Html.fromHtml(value));
textView.setTextColor(textColor);
textView.setTextSize(textSize);
addView(textView);
}
}
}
private class DownloadWork extends Thread {
private String imageUrl;
private ImageView imageView;
public DownloadWork(String imageUrl, ImageView imageView) {
this.imageUrl = imageUrl;
this.imageView = imageView;
}
@Override
public void run() {
URL url = null;
Drawable drawable = null;
int newImageWidth = 0;
int newImageHeight = 0;
try {
url = new URL(imageUrl);
drawable = Drawable.createFromStream(url.openStream(), "image");
// 对图片进行缩放
newImageWidth = drawable.getIntrinsicWidth() / 3;
newImageHeight = drawable.getIntrinsicHeight() / 3;
} catch (Exception e) {
e.printStackTrace();
}
SystemClock.sleep(2000);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("imageView", imageView);
map.put("drawable", drawable);
Message msg = handler.obtainMessage();
msg.obj = map;
msg.arg1 = newImageWidth;
msg.arg2 = newImageHeight;
handler.sendMessage(msg);
}
}
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
@SuppressWarnings("unchecked")
HashMap<String, Object> map = (HashMap<String, Object>) msg.obj;
ImageView imageView = (ImageView) map.get("imageView");
LayoutParams params = new LayoutParams(msg.arg1, msg.arg2);
params.gravity = Gravity.CENTER_HORIZONTAL;
imageView.setLayoutParams(params);
Drawable drawable = (Drawable) map.get("drawable");
imageView.setImageDrawable(drawable);
}
};
}
2.7MainActivity.java
[java]
view plaincopyprint?
package com.custom.textview;
import java.util.ArrayList;
import java.util.HashMap;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
private final String text = " <p> 今年浙江卫视凭《中国好声音》一举做大" +
",其巨大的影响力直接波及到了各家卫视“跨年晚会”的战略部署。日前" +
",“跨年晚会”概念的鼻祖湖南卫视率先表示“退出跨年烧钱大战”。" +
"但据湖南卫视内部人士透露,即使如此,今年的湖南跨年晚会也将会掂出“跨年季”这个概念" +
",“也就是从12月27日到12月31日,连续五天,我们将相继用《百变大咖秀》、《快乐大本营》" +
"、《女人如歌》、《天天向上》的特别节目来连续打造这个”季“的概念,直到12月31日的那场晚会。”</p>";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 采集显示内容数据
ArrayList<HashMap<String, String>> data = new ArrayList<HashMap<String,String>>();
HashMap<String, String> part1 = new HashMap<String, String>();
part1.put("type", "image");
part1.put("value", "http://www.linuxidc.com/upload/2012_12/121218101020341.png");
HashMap<String, String> part2 = new HashMap<String, String>();
part2.put("type", "text");
part2.put("value", text);
HashMap<String, String> part3 = new HashMap<String, String>();
part3.put("type", "image");
part3.put("value", "http://www.linuxidc.com/upload/2012_12/121218101020341.png");
data.add(part1);
data.add(part2);
data.add(part3);
CustomTextView customTextView = (CustomTextView) findViewById(R.id.textView);
customTextView.setText(data);
}
}
3案例效果展示
TableLayout经常用到的属性有:
android:collapseColumns:以第0行为序,隐藏指定的列:
android:collapseColumns该属性为空时,效果如下图:
![](http://files.jb51.net/file_images/article/201211/201211071001322.jpg)
把android:collapseColumns=0,2--------------》意思是把第0和第2列去掉,如下图:
![](http://files.jb51.net/file_images/article/201211/201211071001323.jpg)
android:shrinkColumns:以第0行为序,自动延伸指定的列填充可用部分:
当LayoutRow里面的控件还没有布满布局时,shrinkColumns不起作用,如下图:
![](http://files.jb51.net/file_images/article/201211/201211071001324.jpg)
设置了shrinkColumns=0,1,2,布局完全没有改变,因为LayoutRow里面还剩足够的空间。
当LayoutRow布满控件时,如下图:
![](http://files.jb51.net/file_images/article/201211/201211071001325.jpg)
设置设置了shrinkColumns=2,则结果如下图,控件自动向垂直方向填充空间:
![](http://files.jb51.net/file_images/article/201211/201211071001326.jpg)
android:stretchColumns:以第0行为序,尽量把指定的列填充空白部分:
![](http://files.jb51.net/file_images/article/201211/201211071001327.jpg)
设置stretchColumns=1,则结果如下图,第1列被尽量填充(Button02与TextView02同时向右填充,直到TextView03被压挤到最后边)。
![](http://files.jb51.net/file_images/article/201211/201211071001328.jpg)
相关文章推荐
- Android应用view组件tablelayout应用(tablerow中的属性的应用)
- 说说Android 两种为自定义组件添加属性的使用方法和区别 推荐
- Android实现卫星菜单(一)自定义属性及重写onMeasure、onLayout方法
- 【android 开发知识积累】——属性(Attribute)资源的使用和自定义View组件
- Android中自定义组件及自定义属性
- Android TableLayout 常用的属性介绍及演示
- android -> 通过自定义的TableLayout实现网格形的RadioButton
- 【android开发记录片】2.自定义/定制 Dialog组件
- Android自定义View以及layout属性全攻略
- Android中自定义组件及自定义属性
- Android 布局详解 -三表格布局(TableLayout)以及重要属性
- 【android开发记录片】2.自定义/定制 Dialog组件
- 对于android中自定义组件属性的理解
- android 自定义属性通过反射关联组件与方法
- Android TableLayout 常用的属性介绍及演示
- Android中自定义组件和它的属性
- android attrs组件自定义属性
- Android 两种为自定义组件添加属性的使用方法和区别
- Android,xml组件属性style的使用,自定义适配器(含持有者模式)
- Android 自定义组件属性方式