文本控件
在TextView中预定义了一些类似HTML标签(不区分大小写),通过这些标签,我们可以使TextView控件显示不同的颜色、大小、字体的文字。
常见的标签如下:
名称 | 描述 |
---|---|
|
设置颜色和字体 ,只支持color和face两个属性 |
|
大号字体 |
|
小号字体 |
|
斜体 |
|
粗体 |
|
等宽字体(Monospace) |
|
换行(行与行之间没有空行),相当于\n |
|
换行(行与行之间有空行),相当于\n\n. 对于带有标签的文本,直接使\n无法换行,只能使用 或者
|
|
超链接 |
|
插入图像,只有一个src属性 |
虽然和HTML标签类似,但是并不具备HTML标签的全部功能。
不能将带有标签的字符串直接使用TextView.setText()的方法进行设置,需要使用Html.fromHtml()将带有标签的字符串转换成CharSequence对象,然后再使用TextView.setText()方法进行设置。
如果想要在显示的文本中将URL、Email、电话号码等特殊内容高亮显示,并在单击的时候触发相关的动作(URL会调用浏览器显示网址,电话号码会在拨号界面显示电话号),可以通过设置
标签的android.autoLink属性来实现
名称 | 描述 |
---|---|
none | 不匹配任何链接(默认值) |
web | 匹配Web网址 |
匹配Email | |
phone | 匹配电话号码 |
map | 匹配映射地址 |
all | 匹配所有的连接 |
Demo:
android:autoLink=”all”
<TextView
android:id="@+id/id_tv_richText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/id_tv_richText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="all"/>
public class RichTextViewAct extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rich_text_view);
init();
}
private void init() {
TextView textView1 = (TextView) findViewById(R.id.id_tv_richText1);
TextView textView2 = (TextView) findViewById(R.id.id_tv_richText2);
String html = "I Love Android
";
html += "I Love Android"
;
html += "I Love Android"
;
html += "百度";
Log.e("html内容:", html);
// 将预定义标签的字符串转换成CharSequence对象
CharSequence charSequence = Html.fromHtml(html);
Log.e("charSequence:", charSequence.toString());
// 为第一个TextView设置文本
textView1.setText(charSequence);
// 这行代码只管重要,没有,无法单击链接调用浏览器显示网页
textView1.setMovementMethod(LinkMovementMethod.getInstance());
// 第二个TextVie要显示的文本
StringBuffer sb = new StringBuffer();
sb.append("我的URL: http://www.baidu.com\n");
sb.append("我的Email: [email protected]\n");
sb.append("我的电话:12345678909");
textView2.setText(sb.toString());
textView2.setMovementMethod(LinkMovementMethod.getInstance());
}
}
注意
在调用setText方法设置文本完成后,还需要调用 setMovementMethod方法设置一个MovementMethod对象。 由于本例中标签是链接,因此,需要使用LinkMovementMethod.getInstance()方法获得MovementMethod对象,该对象可以使单击浏览器时显示指定的网页,如果不设置MovementMethod对象,虽然可以正常显示a标签指定的链接,但是单击链接任何反应。
<img>标签可以实现。
img标签只有一个src属性,该属性原则上应该指向一个图像地址或可以找到某个图像资源的唯一标识,但是系统并不会直接根据src属性所指的值自动获取和显示图像,需要开发人员解析。 解析src属性值的工作需要在ImageGetter对象的getDrawable方法中完成。
ImageGetter是个接口。使用过Html.fromHtml方法的如下重载形式会比较熟悉它。
public static Spanned fromHtml(String source,ImageGetter imageGetter ,TagHandler tagHandler);
fromHtml方法有如下三个参数:
Demo: 5张图片,存放在res/drawable文件夹下,在一个TextView中以不同的大小显示这5张图片,并在其中插入相应的文字。
由于无法直接使用文件名来引用res/drawable中的图像资源,我们使用反射技术从R.drawable类中通过图像资源名称获取对应的图像资源ID,实现的原理就是R.drawable类中的相应的资源ID变量名就是图像文件的文件名。
public class MultTextPicAct extends Activity {
private TextView tv_textAndPic;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_mult_text_pic);
initView();
}
/**
* 初始化视图
*/
private void initView() {
// 组件初始化
tv_textAndPic = (TextView) findViewById(R.id.id_tv_textAndPic);
tv_textAndPic.setTextSize(20f);
tv_textAndPic.setBackgroundColor(Color.WHITE);
// 定义图文混编
String html = "图片1图片2"
;
html += "图片3
";
html += "图片4"
;
html += "图片5";
//使用Html.fromHtml()转换包含Html标签的文本,需要指定第二个参数
CharSequence charSequence = Html.fromHtml(html, new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
// 装载图像资源
Drawable drawable = getResources().getDrawable(getResourceId(source));
// 第三个图片按50%等比压缩 ,其余按原大小显示
if ("tag_blue".equals(source)) {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth() / 2, drawable.getIntrinsicHeight() / 2);
} else {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
}
return drawable;
}
}, null);
tv_textAndPic.setText(charSequence);
// 有超链接标签,需设置LinkMovementMethod,否则点击无相应
tv_textAndPic.setMovementMethod(LinkMovementMethod.getInstance());
}
/**
* 利用反射从R.drawable类中通过图像资源名称获取对应的图像资源ID
*
* @param name 表示res/drawable中的图像文件名(不含扩展名)
* @return 图像资源ID
*/
private int getResourceId(String name) {
try {
// 根据资源的ID变量名(也就是图像资源的文件名),获得Field字段
Field field = R.drawable.class.getField(name);
// 取得并返回资源ID(静态变量)的值
return Integer.valueOf(field.get(null).toString());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return 0;
}
}
注意:在getDrawable方法中获取到图像资源的drawable对象后,必须使用Drawable.setBounds方法设置图像的显示区域,否则显示区域的面积为0,也就不会在TextView中显示图像了。其中第三个图像等比缩小了50%,显示效果如下
我们知道通过标签以及TextView自动识别的特殊文本(网址 电话 Email等),这些都可以通过单击操作来触发不同的动作。虽然这些单击动作已经可以满足大部分的需求了,但是如果要想在单击链接的时候执行任意的自定义的动作,就需要学习下面的内容了。
在Android中,Span表示一段文本的效果,例如链接形式,图像,带颜色的文本等。
所有的Span类都在android.text.style包中。
Demo:
准备一个TextView,点击跳转到Activity。
我们使用SpannableString对象来设置Span。
SpannableString和SpannableBuilder的区别:SpannableString不允许修改文本,只允许设置Span,而SpannableBulilder既允许修改文本,也允许设置Span。
public class Jump2Activity extends Activity {
private TextView tv_jump ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_jump2);
initData();
}
/**
* 点击TextView弹出Activity
*/
private void initData() {
tv_jump = (TextView)findViewById(R.id.id_tv_jump2Act);
String text = "显示Activity";
// 将文本转换成SpannableString对象
SpannableString spannableString = new SpannableString(text);
// 将text中的所有文本设置成ClickableSpan对象,并实现onClick方法
spannableString.setSpan(new ClickableSpan() {
// 在onClick方法中可以编写单击链接时要执行的动作
@Override
public void onClick(View widget) {
startActivity(new Intent(Jump2Activity.this,JumpTerminalAct.class));
}
},0,text.length() , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// 设置控件显示内容
tv_jump.setText(spannableString);
// 在点击链接时凡是要有执行的动作,都必须要设置MovementMethod对象
tv_jump.setMovementMethod(LinkMovementMethod.getInstance());
}
}
方法说明setSpan 4个参数
public void setSpan(Object what, int start, int end, int flags) {
super.setSpan(what, start, end, flags);
}
第一个参数需要设置一个ClickableSpan对象
第二个和第三个参数表示要设置成Span的某段文本的起始位置和终止位置。
第四个参数是一个标志,在本例中设置成了Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,该标志在TextView中的意义不大,单在EditText控件中表示的含义:在当前Span效果的前后输入字符串时并不应用Span的效果。
还有其他的几个值:
Spanned.SPAN_EXCLUSIVE_INCLUSIVE :在Span前面输入的字符不应用Span的效果,后面输入的字符应用Span的效果
Spanned.SPAN_INCLUSIVE_INCLUSIVE:在Span前面输入的字符应用Span的效果,后面输入的字符不应用Span的效果
Spanned.SPAN_INCLUSIVE_EXCLUSIVE:在Span前后输入的字符都应用Span的效果。
从上面的例子中我们可以总结出 设置字符串中的某个子字符串的样式(变成可单击的链接、设置字体等)步骤如下:
在SDK的android.text.style有很多现成的Span对象,例如BackgroundColorSpan,该类的功能是设置指定字符串的背景色。
例如:
TextView textView = (TextView)findViewById(R.id.textView);
String text = "<没有背景><黄色背景>";
// 第一步:将字符串转换成为SpannableString对象
SpannableString s = new SpannableString(text);
// 第二步:确定要设置的子字符串的star和end
int start = 6 ;
int end = 12 ;
// 第三步: 创建BackgroundColorSpan对象
BackgroundColorSpan b = new BackgroundColor(Color.YELLOW);
// 第四步:使用setSpan将指定的子字符串转换成BackgroundColorSpan对象
s.setSpan(b,start,end,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// 第五步:用SpannableString对象设置TextView控件
textView.setText(s);
BackgroundColorSpan只能够设置文字的背景色,为了更加的通用,自定义一个ColorSpan类,使其能够同时设置文字颜色和背景色(android.text.style.ForegroundColorSpan可以设置文字颜色,但并没有可以同事设置背景和文字颜色的Span类)。
如果需要处理链接动作,必须要继承ClickableSpan类,本例我们只是设置文字和背景颜色,并不需要处理任何动作,因此只需要从CharacterStyle类继承即可。事实上,ClickableSpan也是CharacterStyle的子类。
代码如下:
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.BackgroundColorSpan;
import android.text.style.CharacterStyle;
import android.widget.TextView;
import com.turing.base.R;
public class AddBackgroundAct extends Activity {
private TextView tv_addbBackground;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_background);
initView();
}
private void initView() {
tv_addbBackground = (TextView) findViewById(R.id.id_tv_addBackground);
String text = "<没有背景><黄色背景>\n\n<蓝色背景,红色文字>";
SpannableString spannableString = new SpannableString(text);
int start = 6;
int end = 12;
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.YELLOW);
spannableString.setSpan(backgroundColorSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// <蓝色背景,红色文字> (每个 “\n”算一个长度)
start = 14;
end = text.length();
// 创建ColorSpan
ColorSpan colorSpan = new ColorSpan(Color.RED, Color.BLUE);
// 将文字转换为ColorSpan对象
spannableString.setSpan(colorSpan, start,end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv_addbBackground.setText(spannableString);
TextView tv = (TextView)findViewById(R.id.id_tv_tv2);
tv.setText("一整个字符串的普通的背景设置,文字颜色设置");
tv.setBackgroundColor(Color.GREEN);
tv.setTextColor(Color.DKGRAY);
}
/**
* 自定义Span类,可以同时设置文字颜色和背景色
*/
class ColorSpan extends CharacterStyle {
private int mTextColor;
private int mBackgroundColor;
public ColorSpan(int mTextColor, int mBackgroundColor) {
this.mTextColor = mTextColor;
this.mBackgroundColor = mBackgroundColor;
}
// 重写updateDrawState方法
@Override
public void updateDrawState(TextPaint tp) {
tp.bgColor = mBackgroundColor;
tp.setColor(mTextColor);
}
}
}
总结:
等,不要设置android:autoLink属性
标签(仅支持a标签)设置可点击的链接,不要设置android:autoLink属性。例如<string name="link_text">
<a href="tel:123456">打电话a>
string>
然后在TextView标签中引用
.....
android:text="@string/link_text"
两种方式:
通过第一中方式实现:
public class BorderTextView extends TextView {
public BorderTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
// 设置所绘制的边框颜色为黑色
paint.setColor(Color.BLACK);
// 绘制上边框
canvas.drawLine(0, 0, this.getWidth() - 1, 0, paint);
// 绘制左边框
canvas.drawLine(0, 0, 0, this.getHeight() - 1, paint);
// 绘制右边框
canvas.drawLine(this.getWidth() - 1, 0, this.getWidth() - 1, this.getHeight() - 1, paint);
// 绘制下边框
canvas.drawLine(0, this.getHeight() - 1, this.getWidth() - 1, this.getHeight() - 1, paint);
}
}
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.turing.base.activity.textViewAct.BorderTextView
android:id="@+id/id_tv_borderTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:padding="10dp"
android:gravity="center"
android:text="自定义TextView绘制边框"/>
RelativeLayout>
如果TextView控件中显示了多行文本,会有一个默认的行间距。
如果要改默认的行间距,三种方法:
android:lineSpacingExtra设置精确的行间距,例如
android:lineSpacingExtra="20dp"
android:lineSpacingMultiplier 属性设置的是默认行间距的倍数。
如果同时设置了这两个属性,以较大行间距为准。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#000">
<TextView
android:id="@+id/id_tv_lineSpace"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_margin="10dp"
android:background="#FFF"
android:lineSpacingExtra="20dp"
android:textColor="#000"
android:text="第一行的文本\n第二行的文本(20dp)"/>
<TextView
android:id="@+id/id_tv_lineSpace2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_margin="10dp"
android:background="#FFF"
android:lineSpacingMultiplier="1.8"
android:textColor="#000"
android:text="第一行的文本\n第二行的文本(行间距是默认行间距的1.8倍)"/>
<TextView
android:id="@+id/id_tv_lineSpace3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_margin="10dp"
android:background="#FFF"
style="@style/line_space"
android:textColor="#000"
android:text="第一行的文本\n第二行的文本(style设置的,行间距是默认行间距的1.5倍)"/>
<TextView
android:id="@+id/id_tv_lineSpace4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_margin="10dp"
android:background="#FFF"
android:textColor="#000"
android:text="第一行的文本\n第二行的文本(代码设置)"/>
LinearLayout>
<style name="line_space">
<item name="android:lineSpacingMultiplier">1.5item>
style>
public class LineSpaceTextViewAct extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_line_space_text_view);
TextView tv = (TextView)findViewById(R.id.id_tv_lineSpace4);
tv.setLineSpacing(50,1.2f);
}
}
setSpacing 方法:
/**
* Sets line spacing for this TextView. Each line will have its height
* multiplied by mult
and have add
added to it.
*
* @attr ref android.R.styleable#TextView_lineSpacingExtra
* @attr ref android.R.styleable#TextView_lineSpacingMultiplier
*/
public void setLineSpacing(float add, float mult) {
if (mSpacingAdd != add || mSpacingMult != mult) {
mSpacingAdd = add;
mSpacingMult = mult;
if (mLayout != null) {
nullLayouts();
requestLayout();
invalidate();
}
}
}
第一个参数相当于 android:lineSpacingExtra属性,第二个参数相当于android:lineSpaceingMultiplier属性。系统会采用哪个参数作为最终的行间距,取决于哪个参数值所表示的行间距大了。
当文本内容太多的时候,控件一行显示不开的时候,系统默认的会在最后显示一个省略号(…)
通过android:ellipsize属性可以设置省略号的位置,当属性值为none的时候则不显示省略号,默认在对后面加省略号。
需要设置 android:singleLine=”true”
代码设置如下:
textView.setEllipsize(TextUtils.TruncateAt.END);
xml报文设置:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
android:orientation="vertical">
<TextView
android:id="@+id/id_tv_ignore1"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:background="#FFF"
android:ellipsize="start"
android:singleLine="true"
android:layout_margin="10dp"
android:text="维基百科的目标是建立拥有人类全部知识的百科全书" />
<TextView
android:id="@+id/id_tv_ignore2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFF"
android:ellipsize="middle"
android:singleLine="true"
android:layout_margin="10dp"
android:text="维基百科的目标是建立拥有人类全部知识的百科全书dddddddddddddddddddddd" />
<TextView
android:id="@+id/id_tv_ignore3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFF"
android:ellipsize="end"
android:singleLine="true"
android:layout_margin="10dp"
android:text="维基百科的目标是建立拥有人类全部知识的百科全书ddddddddddddddddddd" />
LinearLayout>
android:marqueeRepeatLimit=“marquee_forever”或者是大于0的整数,marquee_forever表示永远循环显示。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#FFF"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:text="李克勤(Hacken Lee),生于香港,籍贯广东新会崖西,中国香港歌手,演员,主持人" />
LinearLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000">
<TextView
android:id="@+id/id_tv_scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFF"
android:singleLine="false"
android:maxLines="4"
android:scrollbars="vertical"
android:scrollbarStyle="outsideOverlay"
android:scrollbarFadeDuration="2000"
android:padding="10dp"
android:text="周杰伦, 生于中华民国台北县林口乡,是台湾著名国语流行音乐男歌手、演员、导演及音乐创作人。 周杰伦于2000年正式出道并发行其个人首张同名国语专辑《Jay》,翌年凭借该张专辑获得第十二届台湾金曲奖“最佳流行音乐演唱专辑奖”ddddddddddddddddddddddddddddddddddddddddddddddd。"/>
RelativeLayout>
public class ScrollTextViewAct extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scroll_text_view);
TextView textView = (TextView) findViewById(R.id.id_tv_scroll);
textView.setMovementMethod(ScrollingMovementMethod.getInstance());
}
}
android:scrollbars=”vertical” : 垂直滚动必须为vertical
android:scrollbarStyle=”outsideOverlay” :滚动条在文字的右侧显示。如果insideOVerlay滚动条会在右侧文字上显示(会覆盖文字的一部分)。
android:scrollbarFadeDuration=”2000” 滚动条从出现到消失(以渐变的方式)的时间,单位是毫秒