一、问题在哪里?
textview显示长文字时会进行自动折行,如果遇到一些特殊情况,自动折行会杯具成这个样子:
上述特殊情况包括:
1)全角/半角符号混排(一般是数字、字母、汉字混排)
2)全角/半角标点符号出现在行首时,该标点符号会连同其前一个字符跳到下一行
3)英文单词不能被折成两行
4)......
[转载请保留本文地址:http://www.cnblogs.com/goagent/p/5159125.html]
二、怎么搞?
通常有两类解决方案:
1)修改文本内容,将所有符号全角化、在标点符号前面加空格等等……
2)保持文本内容不变,在合适的位置将文本手动分成多行
本文采用第二种方案,更加通用,也最大限度的保留了原文本。
[转载请保留本文地址:http://www.cnblogs.com/goagent/p/5159125.html]
三、开始干活
3.1 “在合适的位置将文本手动分成多行”需要知道textview的实际宽度、字体大小等信息,框架如下:
1 public class TestCActivity extends Activity { 2 private TextView mText; 3 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 8 setContentView(R.layout.testc); 9 10 mText = (TextView)findViewById(R.id.txt); 11 mText.setText("本文地址http://www.cnblogs.com/goagent/p/5159125.html本文地址啊本文。地址。啊http://www.cnblogs.com/goagent/p/5159125.html"); 12 mText.getViewTreeObserver().addOnGlobalLayoutListener(new OnTvGlobalLayoutListener()); 13 } 14 15 private class OnTvGlobalLayoutListener implements OnGlobalLayoutListener { 16 @Override 17 public void onGlobalLayout() { 18 mText.getViewTreeObserver().removeOnGlobalLayoutListener(this); 19 final String newText = autoSplitText(mText); 20 if (!TextUtils.isEmpty(newText)) { 21 mText.setText(newText); 22 } 23 } 24 } 25 26 private String autoSplitText(final TextView tv) { 27 final String rawText = tv.getText().toString(); 28 final Paint tvPaint = tv.getPaint(); 29 final int tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); 30 31 //autoSplitText begin.... 32 String newText = rawText; 33 //autoSplitText end.... 34 35 return newText; 36 } 37 }
3.2 实现自动分割文本,简单来说就是用textview的paint逐字符测量,如果发现当前行绘制不下了,就手动加入一个换行符:
1 private String autoSplitText(final TextView tv) { 2 final String rawText = tv.getText().toString(); //原始文本 3 final Paint tvPaint = tv.getPaint(); //paint,包含字体等信息 4 final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //控件可用宽度 5 6 //将原始文本按行拆分 7 String [] rawTextLines = rawText.replaceAll("\r", "").split("\n"); 8 StringBuilder sbNewText = new StringBuilder(); 9 for (String rawTextLine : rawTextLines) { 10 if (tvPaint.measureText(rawTextLine) <= tvWidth) { 11 //如果整行宽度在控件可用宽度之内,就不处理了 12 sbNewText.append(rawTextLine); 13 } else { 14 //如果整行宽度超过控件可用宽度,则按字符测量,在超过可用宽度的前一个字符处手动换行 15 float lineWidth = 0; 16 for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) { 17 char ch = rawTextLine.charAt(cnt); 18 lineWidth += tvPaint.measureText(String.valueOf(ch)); 19 if (lineWidth <= tvWidth) { 20 sbNewText.append(ch); 21 } else { 22 sbNewText.append("\n"); 23 lineWidth = 0; 24 --cnt; 25 } 26 } 27 } 28 sbNewText.append("\n"); 29 } 30 31 //把结尾多余的\n去掉 32 if (!rawText.endsWith("\n")) { 33 sbNewText.deleteCharAt(sbNewText.length() - 1); 34 } 35 36 return sbNewText.toString(); 37 }
3.3 话不多说,效果如下:
[转载请保留本文地址:http://www.cnblogs.com/goagent/p/5159125.html]
四、更多玩法
4.1 可以封装一个自定义的textview,直接包含自动排版换行的功能:
1 import android.content.Context; 2 import android.graphics.Paint; 3 import android.text.TextUtils; 4 import android.util.AttributeSet; 5 import android.widget.TextView; 6 7 public class AutoSplitTextView extends TextView { 8 private boolean mEnabled = true; 9 10 public AutoSplitTextView(Context context) { 11 super(context); 12 } 13 14 public AutoSplitTextView(Context context, AttributeSet attrs) { 15 super(context, attrs); 16 } 17 18 public AutoSplitTextView(Context context, AttributeSet attrs, int defStyle) { 19 super(context, attrs, defStyle); 20 } 21 22 public void setAutoSplitEnabled(boolean enabled) { 23 mEnabled = enabled; 24 } 25 26 @Override 27 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 28 if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 29 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY 30 && getWidth() > 0 31 && getHeight() > 0 32 && mEnabled) { 33 String newText = autoSplitText(this); 34 if (!TextUtils.isEmpty(newText)) { 35 setText(newText); 36 } 37 } 38 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 39 } 40 41 private String autoSplitText(final TextView tv) { 42 final String rawText = tv.getText().toString(); //原始文本 43 final Paint tvPaint = tv.getPaint(); //paint,包含字体等信息 44 final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //控件可用宽度 45 46 //将原始文本按行拆分 47 String [] rawTextLines = rawText.replaceAll("\r", "").split("\n"); 48 StringBuilder sbNewText = new StringBuilder(); 49 for (String rawTextLine : rawTextLines) { 50 if (tvPaint.measureText(rawTextLine) <= tvWidth) { 51 //如果整行宽度在控件可用宽度之内,就不处理了 52 sbNewText.append(rawTextLine); 53 } else { 54 //如果整行宽度超过控件可用宽度,则按字符测量,在超过可用宽度的前一个字符处手动换行 55 float lineWidth = 0; 56 for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) { 57 char ch = rawTextLine.charAt(cnt); 58 lineWidth += tvPaint.measureText(String.valueOf(ch)); 59 if (lineWidth <= tvWidth) { 60 sbNewText.append(ch); 61 } else { 62 sbNewText.append("\n"); 63 lineWidth = 0; 64 --cnt; 65 } 66 } 67 } 68 sbNewText.append("\n"); 69 } 70 71 //把结尾多余的\n去掉 72 if (!rawText.endsWith("\n")) { 73 sbNewText.deleteCharAt(sbNewText.length() - 1); 74 } 75 76 return sbNewText.toString(); 77 } 78 }
4.2 实现悬挂缩进
1 private String autoSplitText(final TextView tv, final String indent) { 2 final String rawText = tv.getText().toString(); //原始文本 3 final Paint tvPaint = tv.getPaint(); //paint,包含字体等信息 4 final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //控件可用宽度 5 6 //将缩进处理成空格 7 String indentSpace = ""; 8 float indentWidth = 0; 9 if (!TextUtils.isEmpty(indent)) { 10 float rawIndentWidth = tvPaint.measureText(indent); 11 if (rawIndentWidth < tvWidth) { 12 while ((indentWidth = tvPaint.measureText(indentSpace)) < rawIndentWidth) { 13 indentSpace += " "; 14 } 15 } 16 } 17 18 //将原始文本按行拆分 19 String [] rawTextLines = rawText.replaceAll("\r", "").split("\n"); 20 StringBuilder sbNewText = new StringBuilder(); 21 for (String rawTextLine : rawTextLines) { 22 if (tvPaint.measureText(rawTextLine) <= tvWidth) { 23 //如果整行宽度在控件可用宽度之内,就不处理了 24 sbNewText.append(rawTextLine); 25 } else { 26 //如果整行宽度超过控件可用宽度,则按字符测量,在超过可用宽度的前一个字符处手动换行 27 float lineWidth = 0; 28 for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) { 29 char ch = rawTextLine.charAt(cnt); 30 //从手动换行的第二行开始,加上悬挂缩进 31 if (lineWidth < 0.1f && cnt != 0) { 32 sbNewText.append(indentSpace); 33 lineWidth += indentWidth; 34 } 35 lineWidth += tvPaint.measureText(String.valueOf(ch)); 36 if (lineWidth <= tvWidth) { 37 sbNewText.append(ch); 38 } else { 39 sbNewText.append("\n"); 40 lineWidth = 0; 41 --cnt; 42 } 43 } 44 } 45 sbNewText.append("\n"); 46 } 47 48 //把结尾多余的\n去掉 49 if (!rawText.endsWith("\n")) { 50 sbNewText.deleteCharAt(sbNewText.length() - 1); 51 } 52 53 return sbNewText.toString(); 54 }
调用方式:
autoSplitText(tv, "1、");
悬挂缩进效果:
[转载请保留本文地址:http://www.cnblogs.com/goagent/p/5159125.html]
时间: 2024-10-04 18:31:22