Android自定义TextView排版优化

来源:互联网 发布:单片机 脉冲信号 编辑:程序博客网 时间:2024/05/16 12:08

今天的文章关于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


0 0