当前位置:   article > 正文

android textview 自动换行 整齐排版_textview 设置平铺所有

textview 设置平铺所有

一、问题在哪里?

textview显示长文字时会进行自动折行,如果遇到一些特殊情况,自动折行会杯具。

特殊情况包括:

1)全角/半角符号混排(一般是数字、字母、汉字混排)

2)全角/半角标点符号出现在行首时,该标点符号会连同其前一个字符跳到下一行

3)英文单词不能被折成两行

4)......

二、怎么搞?

通常有两类解决方案:

1)修改文本内容,将所有符号全角化、在标点符号前面加空格等等……

2)保持文本内容不变,在合适的位置将文本手动分成多行

本文采用第二种方案,更加通用,也最大限度的保留了原文本。

 [转载请保留本文地址:http://www.cnblogs.com/snser/p/5159125.html]

三、开始干活

3.1  “在合适的位置将文本手动分成多行”需要知道textview的实际宽度、字体大小等信息,框架如下:

  1. public class TestCActivity extends Activity {
  2. private TextView mText;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.testc);
  7. mText = (TextView)findViewById(R.id.txt);
  8. mText.setText("本文地址http://www.cnblogs.com/goagent/p/5159125.html本文地址啊本文。地址。啊http://www.cnblogs.com/goagent/p/5159125.html");
  9. mText.getViewTreeObserver().addOnGlobalLayoutListener(new OnTvGlobalLayoutListener());
  10. }
  11. private class OnTvGlobalLayoutListener implements OnGlobalLayoutListener {
  12. @Override
  13. public void onGlobalLayout() {
  14. mText.getViewTreeObserver().removeOnGlobalLayoutListener(this);
  15. final String newText = autoSplitText(mText);
  16. if (!TextUtils.isEmpty(newText)) {
  17. mText.setText(newText);
  18. }
  19. }
  20. }
  21. private String autoSplitText(final TextView tv) {
  22. final String rawText = tv.getText().toString();
  23. final Paint tvPaint = tv.getPaint();
  24. final int tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight();
  25. //autoSplitText begin....
  26. String newText = rawText;
  27. //autoSplitText end....
  28. return newText;
  29. }
  30. }

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. String [] rawTextLines = rawText.replaceAll("\r", "").split("\n");
  7. StringBuilder sbNewText = new StringBuilder();
  8. for (String rawTextLine : rawTextLines) {
  9. if (tvPaint.measureText(rawTextLine) <= tvWidth) {
  10. //如果整行宽度在控件可用宽度之内,就不处理了
  11. sbNewText.append(rawTextLine);
  12. } else {
  13. //如果整行宽度超过控件可用宽度,则按字符测量,在超过可用宽度的前一个字符处手动换行
  14. float lineWidth = 0;
  15. for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) {
  16. char ch = rawTextLine.charAt(cnt);
  17. lineWidth += tvPaint.measureText(String.valueOf(ch));
  18. if (lineWidth <= tvWidth) {
  19. sbNewText.append(ch);
  20. } else {
  21. sbNewText.append("\n");
  22. lineWidth = 0;
  23. --cnt;
  24. }
  25. }
  26. }
  27. sbNewText.append("\n");
  28. }
  29. //把结尾多余的\n去掉
  30. if (!rawText.endsWith("\n")) {
  31. sbNewText.deleteCharAt(sbNewText.length() - 1);
  32. }
  33. return sbNewText.toString();
  34. }

四、更多玩法

4.1  可以封装一个自定义的textview,直接包含自动排版换行的功能:

  1. package cc.snser.test;
  2. import android.content.Context;
  3. import android.graphics.Paint;
  4. import android.text.TextUtils;
  5. import android.util.AttributeSet;
  6. import android.widget.TextView;
  7. public class AutoSplitTextView extends TextView {
  8. private boolean mEnabled = true;
  9. public AutoSplitTextView(Context context) {
  10. super(context);
  11. }
  12. public AutoSplitTextView(Context context, AttributeSet attrs) {
  13. super(context, attrs);
  14. }
  15. public AutoSplitTextView(Context context, AttributeSet attrs, int defStyle) {
  16. super(context, attrs, defStyle);
  17. }
  18. public void setAutoSplitEnabled(boolean enabled) {
  19. mEnabled = enabled;
  20. }
  21. @Override
  22. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  23. if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
  24. && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY
  25. && getWidth() > 0
  26. && getHeight() > 0
  27. && mEnabled) {
  28. String newText = autoSplitText(this);
  29. if (!TextUtils.isEmpty(newText)) {
  30. setText(newText);
  31. }
  32. }
  33. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  34. }
  35. private String autoSplitText(final TextView tv) {
  36. final String rawText = tv.getText().toString(); //原始文本
  37. final Paint tvPaint = tv.getPaint(); //paint,包含字体等信息
  38. final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //控件可用宽度
  39. //将原始文本按行拆分
  40. String [] rawTextLines = rawText.replaceAll("\r", "").split("\n");
  41. StringBuilder sbNewText = new StringBuilder();
  42. for (String rawTextLine : rawTextLines) {
  43. if (tvPaint.measureText(rawTextLine) <= tvWidth) {
  44. //如果整行宽度在控件可用宽度之内,就不处理了
  45. sbNewText.append(rawTextLine);
  46. } else {
  47. //如果整行宽度超过控件可用宽度,则按字符测量,在超过可用宽度的前一个字符处手动换行
  48. float lineWidth = 0;
  49. for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) {
  50. char ch = rawTextLine.charAt(cnt);
  51. lineWidth += tvPaint.measureText(String.valueOf(ch));
  52. if (lineWidth <= tvWidth) {
  53. sbNewText.append(ch);
  54. } else {
  55. sbNewText.append("\n");
  56. lineWidth = 0;
  57. --cnt;
  58. }
  59. }
  60. }
  61. sbNewText.append("\n");
  62. }
  63. //把结尾多余的\n去掉
  64. if (!rawText.endsWith("\n")) {
  65. sbNewText.deleteCharAt(sbNewText.length() - 1);
  66. }
  67. return sbNewText.toString();
  68. }
  69. }
  70. View AutoSplitTextView.java
  1. package cc.snser.test;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. public class TestCActivity extends Activity {
  5. private AutoSplitTextView mText;
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.testc);
  10. mText = (AutoSplitTextView)findViewById(R.id.txt);
  11. mText.setText("本文地址");
  12. }
  13. }
  14. View TestCActivity.java
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@android:color/white"
  6. android:orientation="vertical" >
  7. <cc.snser.test.AutoSplitTextView
  8. android:id="@+id/txt"
  9. android:layout_width="match_parent"
  10. android:layout_height="200dp"
  11. android:layout_marginTop="11dp"
  12. android:layout_marginLeft="11dp"
  13. android:layout_marginRight="11dp"
  14. android:background="@android:color/holo_blue_light"
  15. android:textSize="20sp"
  16. android:textColor="@android:color/black" />
  17. </LinearLayout>
  18. View testc.xml

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. String indentSpace = "";
  7. float indentWidth = 0;
  8. if (!TextUtils.isEmpty(indent)) {
  9. float rawIndentWidth = tvPaint.measureText(indent);
  10. if (rawIndentWidth < tvWidth) {
  11. while ((indentWidth = tvPaint.measureText(indentSpace)) < rawIndentWidth) {
  12. indentSpace += " ";
  13. }
  14. }
  15. }
  16. //将原始文本按行拆分
  17. String [] rawTextLines = rawText.replaceAll("\r", "").split("\n");
  18. StringBuilder sbNewText = new StringBuilder();
  19. for (String rawTextLine : rawTextLines) {
  20. if (tvPaint.measureText(rawTextLine) <= tvWidth) {
  21. //如果整行宽度在控件可用宽度之内,就不处理了
  22. sbNewText.append(rawTextLine);
  23. } else {
  24. //如果整行宽度超过控件可用宽度,则按字符测量,在超过可用宽度的前一个字符处手动换行
  25. float lineWidth = 0;
  26. for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) {
  27. char ch = rawTextLine.charAt(cnt);
  28. //从手动换行的第二行开始,加上悬挂缩进
  29. if (lineWidth < 0.1f && cnt != 0) {
  30. sbNewText.append(indentSpace);
  31. lineWidth += indentWidth;
  32. }
  33. lineWidth += tvPaint.measureText(String.valueOf(ch));
  34. if (lineWidth <= tvWidth) {
  35. sbNewText.append(ch);
  36. } else {
  37. sbNewText.append("\n");
  38. lineWidth = 0;
  39. --cnt;
  40. }
  41. }
  42. }
  43. sbNewText.append("\n");
  44. }
  45. //把结尾多余的\n去掉
  46. if (!rawText.endsWith("\n")) {
  47. sbNewText.deleteCharAt(sbNewText.length() - 1);
  48. }
  49. return sbNewText.toString();
  50. }

调用方式:

 autoSplitText(tv, "1、"); 

悬挂缩进效果:

 

转载至:http://www.cnblogs.com/snser/p/5159125.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/242842
推荐阅读
相关标签
  

闽ICP备14008679号