解决android系统TextView自动换行不美观问题

android系统中的textview会在行尾是连串的数字、字母或者标点符号时提前换行,其实word中也是会提前换行的,但是PC端毕竟字符占的空间比例比较小,手机字符占的比例就很大,所以有时候系统自带textview显示行尾会有很大的空白比例,非常难看。所以我们在这种情况下有必要做一个控件用来显示文本。

public class AutoBreakTextView extends TextView {

public static int m_iTextHeight; // 文本的高度
public static int m_iTextWidth;// 文本的宽度

private Paint mPaint = null;
private String string = "";
private float LineSpace = 0;// 行间距
private int padding;

public AutoBreakTextView(Context context, AttributeSet set) {
super(context, set);

WindowManager manager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(dm);
System.out.println("width------>" + dm.widthPixels);
System.out.println("density-------------->" + dm.density);
m_iTextWidth = (int) (dm.widthPixels - 2 * padding - (10 * 4 * dm.density)) + 1;
float textSize = this.getTextSize();
padding = this.getPaddingLeft();
System.out.println("width------------>" + m_iTextWidth);
System.out.println("textSize------------>" + textSize);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(textSize);
mPaint.setColor(Color.GRAY);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

char ch;
int w = 0;
int istart = 0;
int m_iFontHeight;
int m_iRealLine = 0;
int x = padding;
int y = padding;

Vector m_String = new Vector();

FontMetrics fm = mPaint.getFontMetrics();
m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int) LineSpace;// 计算字体高度(字体高度+行间距)

for (int i = 0; i < string.length(); i++) {
ch = string.charAt(i);
float[] widths = new float[1];
String srt = String.valueOf(ch);
mPaint.getTextWidths(srt, widths);

if (ch == '\n') {
m_iRealLine++;
m_String.addElement(string.substring(istart, i));
istart = i + 1;
w = 0;
} else {
w += (int) (Math.ceil(widths[0]));
if (w > m_iTextWidth) {
m_iRealLine++;
m_String.addElement(string.substring(istart, i));
istart = i;
i--;
w = 0;
} else {
if (i == (string.length() - 1)) {
m_iRealLine++;
m_String.addElement(string.substring(istart,
string.length()));
}
}
}
}
canvas.setViewport(m_iTextWidth, m_iTextHeight);
for (int i = 0, j = 1; i < m_iRealLine; i++, j++) {
canvas.drawText((String) (m_String.elementAt(i)), x, y
+ m_iFontHeight * j, mPaint);
}
}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int measuredHeight = measureHeight(heightMeasureSpec);
int measuredWidth = measureWidth(widthMeasureSpec);
System.out.println("measuredHeight------->" + measuredHeight);
this.setMeasuredDimension(measuredWidth, measuredHeight);
this.setLayoutParams(new LinearLayout.LayoutParams(measuredWidth,
measuredHeight));
}

private int measureHeight(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
// Default size if no limits are specified.
initHeight();
int result = m_iTextHeight;
Log.e("measureHeight---------------->", result + "");
return result;
}

private void initHeight() {
m_iTextHeight = 0;

FontMetrics fm = mPaint.getFontMetrics();
int m_iFontHeight = (int) Math.ceil(fm.descent - fm.top)
+ (int) LineSpace;
int line = 0;
int istart = 0;

int w = 0;
for (int i = 0; i < string.length(); i++) {
char ch = string.charAt(i);
float[] widths = new float[1];
String srt = String.valueOf(ch);
mPaint.getTextWidths(srt, widths);

if (ch == '\n') {
line++;
istart = i + 1;
w = 0;
} else {
w += (int) (Math.ceil(widths[0]));
if (w > m_iTextWidth) {
line++;
istart = i;
i--;
w = 0;
} else {
if (i == (string.length() - 1)) {
line++;
}
}
}
}
m_iTextHeight = (line) * m_iFontHeight;
Log.e("m_iTextHeight--------------------->", m_iTextHeight + "");
}

private int measureWidth(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);

// Default size if no limits are specified.
int result = 500;
if (specMode == MeasureSpec.AT_MOST) {
// Calculate the ideal size of your control
// within this maximum size.
// If your control fills the available space
// return the outer bound.
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY) {
// If your control can fit within these bounds return that value.
result = specSize;
}
return result;
}

public void setText(String text) {
string = text;
initHeight();
invalidate();
requestLayout();
}
}

 

没有用到自定义属性,代码不太完美,以后改进

需要注意的是:

canvas.drawText(String str,int x,int y,Paint paint)中的x,y不能是左上角,而是一行的左下角,因为canvas绘制文本是根据基线为基准的

基线如图中baseLine

posted on 2012-06-27 18:05  白涌泉  阅读(8685)  评论(0编辑  收藏  举报