今天的文章关于android中最常用的的控件Textview,安卓中的TextView在文字布局的时候会在每行的末尾进行智能的换行分割,特别是有标点符号等出现的时候。这个规律是怎样的我至今还没有探究过。有兴趣的大家可以自己去看一下TextView的源码。项目中需要对文字进行较舒服的排布,去掉尾部的空缺,所以我对此给出来自己的解决方案,先看效果图吧。
绿色字体是用自定义的TextView加载的文字信息,没有限制最大行数。白色文字是用android系统的TextView。黄色文字是自定义的TextView,限制了最大行数,并且设置了显示自定义省略信息,就是在布局文件中调用android:ellipsize="end"。效果还是很明显的
我这里就简单粗暴的去重写Textview的onDraw方法了,而且没有super,完全是自己用Canvas去绘画每一个文字或者符号。所以一定程度上讲,这更像是一个View,丢失了很多TextView的特性,当然为了保留更多的Textview的特性,我也在里面重写了很多方法,新加入了一些方法。代码给出来,大家可以根据自己的需要自己去拓展。有很多原来TextView的函数都失去了作用,使用的时候请注意。
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* 自定义的文字整齐排版Textview控件,能让文字相对更加的整齐
* <p>
* 在xml布局文件中请加入命名空间"http://hdt.hdt/hdt"用于设置以下属性(单数字不填单位):
* lineSpacingExtra,textSize,paddingLeft,paddingRight。 宽度请设置充满父布局, 目前只支持结尾省略...
*
* @author illidan.huang 杭州
*/
public class MyTextView extends TextView {
private final String namespace = "http://hdt.hdt/hdt";
private String text;
private float textSize;
private Paint paint1 = new Paint();
private float paddingLeft;
private float paddingRight;
private float textShowWidth;
private int textColor;
private float lineSpace;
private int maxLines = Integer.MAX_VALUE;
private boolean ellipsize = false;
private float ellipsizeLength = 0;
private String ellipsizeString = "(未完待续...)";
// 初始化是否需要设置高度,不加判断则会无限的递归onDraw,自己看
private boolean needHieght = true;
private int lineCount = 0;
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
text = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "text");
textSize = attrs.getAttributeIntValue(namespace, "textSize", 10);
textColor = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "textColor", Color.WHITE);
maxLines = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "maxLines", Integer.MAX_VALUE);
String ell = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "ellipsize");
ellipsize = "3".equals(ell);//android:ellipsize="end"对应的值是3,请看安卓源码
paddingLeft = attrs.getAttributeIntValue(namespace, "paddingLeft", 0);
paddingRight = attrs.getAttributeIntValue(namespace, "paddingRight", 0);
lineSpace = attrs.getAttributeIntValue(namespace, "lineSpacingExtra", 3);
float d = context.getResources().getDisplayMetrics().density;
textSize = d * textSize + 0.5f;
lineSpace = d * lineSpace + 0.5f;
if(maxLines <= 0){
maxLines = Integer.MAX_VALUE;
}
paint1.setTextSize(textSize);
paint1.setColor(textColor);
paint1.setAntiAlias(true);
textShowWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth() - paddingLeft - paddingRight;
ellipsizeLength = paint1.measureText(ellipsizeString);
}
@Override
protected void onDraw(Canvas canvas) {
int lineCount = 0;
char[] textCharArray = text.toCharArray();
float drawedWidth = 0;
float charWidth;
for (int i = 0; i < textCharArray.length; i++) {
charWidth = paint1.measureText(textCharArray, i, 1);
// 这里是用于,设置了最大行数和末尾省略的情况下进行的判断,16完全是我凭感觉给出的数字,没有为什么
if (ellipsize && textShowWidth - drawedWidth - ellipsizeLength < 16) {
if (lineCount == maxLines - 1) {
canvas.drawText(ellipsizeString, paddingLeft + drawedWidth, (lineCount + 1) * textSize + lineSpace
* lineCount, paint1);
break;
}
}
// 跳入下一行判断
if (textShowWidth - drawedWidth < charWidth || textCharArray[i] == '\n') {
lineCount++;
if (lineCount > maxLines - 1) {
lineCount--;
break;
}
drawedWidth = 0;
}
canvas.drawText(textCharArray, i, 1, paddingLeft + drawedWidth, (lineCount + 1) * textSize + lineSpace * lineCount,
paint1);
drawedWidth += charWidth;
}
if (needHieght) {
setHeight((lineCount + 1) * (int) (textSize + lineSpace));
needHieght = false;
}
this.lineCount = lineCount;
}
@Override
public void invalidate() {
needHieght = true;
super.invalidate();
}
@Override
public void setText(CharSequence text, BufferType type) {
// TODO Auto-generated method stub
super.setText(text, type);
this.text = String.valueOf(text);
invalidate();
}
/**
* 设置省略显示内容,默认"。。。"
*
* @param ellString
*/
public final void setEllipsizeString(String ellString) {
this.ellipsizeString = ellString;
}
/**
* 设置结尾是否显示省略内容
*
* @param isEnd
*/
public final void setEllipsizeEnd(boolean isEnd) {
this.ellipsize = isEnd;
}
@Override
public void setMaxLines(int maxlines) {
this.maxLines = maxlines;
if(this.maxLines <= 0){
this.maxLines = Integer.MAX_VALUE;
}
super.setMaxLines(maxlines);
}
@Override
public CharSequence getText() {
return this.text;
}
/**
* 设置行间距
*
* @param spa
*/
public void setLineSpacingExtra(float spa) {
this.lineSpace = spa;
}
@Override
public int getLineCount() {
return lineCount;
}
@Override
public int getLineHeight() {
return (int) (textSize+lineSpace);
}
@Override
public float getTextSize() {
return textSize;
}
@Override
public void setSingleLine() {
setSingleLine(true);
}
@Override
public void setSingleLine(boolean singleLine) {
if(singleLine){
setMaxLines(1);
}else{
setMaxLines(Integer.MAX_VALUE);
}
}
@Override
public void setTextColor(int color) {
this.textColor = color;
paint1.setColor(color);
super.setTextColor(color);
}
}
英文的实现效果我这里暂时未考虑到,需要的话,我给个思路。就是在onDraw函数中,对文字进行分词的时候
char[] textCharArray = text.toCharArray(); 按单词为单位进行分割,而不是一个字符char。
以下是图示的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:hdt="http://hdt.hdt/hdt"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/black"
android:gravity="center_horizontal"
android:orientation="vertical" >
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<com.wigit.MyTextView
android:id="@+id/txt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
hdt:paddingLeft="5"
android:text="【一人之下,万人之上】《意林》卷一引《六韬》:“屈一人下,伸万人上,惟圣人能行之。”《汉书·萧何传》:“夫能诎於一人之下,而信於万乘之上者,汤武是也。”一人,谓天子;万人,谓百官。多指地位崇高权势显赫的大臣。【一人之交】好友;至交。谓亲密如一人。【一夫之用】谓仅能当一人之用,而无兼人之能。【一夫之勇】犹言匹夫之勇。"
android:textColor="#FE8A08"
hdt:lineSpacingExtra="3"
hdt:textSize="16"
></com.wigit.MyTextView>"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="【一人之下,万人之上】《意林》卷一引《六韬》:“屈一人下,伸万人上,惟圣人能行之。”《汉书·萧何传》:“夫能诎於一人之下,而信於万乘之上者,汤武是也。”一人,谓天子;万人,谓百官。多指地位崇高权势显赫的大臣。【一人之交】好友;至交。谓亲密如一人。【一夫之用】谓仅能当一人之用,而无兼人之能。【一夫之勇】犹言匹夫之勇。"
android:textColor="@android:color/white"
android:textSize="16dp" />
<com.wigit.MyTextView
android:id="@+id/txt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
hdt:paddingLeft="5"
android:text="【一人之下,万人之上】《意林》卷一引《六韬》:“屈一人下,伸万人上,惟圣人能行之。”《汉书·萧何传》:“夫能诎於一人之下,而信於万乘之上者,汤武是也。”一人,谓天子;万人,谓百官。多指地位崇高权势显赫的大臣。【一人之交】好友;至交。谓亲密如一人。【一夫之用】谓仅能当一人之用,而无兼人之能。【一夫之勇】犹言匹夫之勇。"
android:textColor="#FE8A08"
hdt:lineSpacingExtra="3"
hdt:textSize="16"
android:maxLines="5"
android:ellipsize="end"
></com.wigit.MyTextView>"
</LinearLayout>
</ScrollView>
</LinearLayout>
若有疑问请下面留言。
若有不足请留言或者联系我,hdtpjhz@163.com