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
|