Android的TextView在显示文字的时候有个问题就是一行还没显示满就跳到下一行,原因是:

1) TextView在显示中文的时候 标点符号不能显示在一行的行首和行尾,如果一个标点符号刚好在一行的行尾,该标点符号就会连同前一个字符跳到下一行显示;

2)一个英文单词不能被显示在两行中( TextView在显示英文时,标点符号是可以放在行尾的,但英文单词也不能分开 );

如果只是想让标点符号可以显示在行尾,有一个简单的方法就是在标点符号后加一个空格,则该标点符号就可以显示在行尾了;

如果想要两端对齐的显示效果,有两种方法:

1)修改Android源代码;将frameworks/base/core/Java/android/text下的StaticLayout.java文件中的如下代码:

[java] view plaincopy
  1. if (c == ' ' || c == '/t' ||
  2. ((c == '.' || c == ',' || c == ':' || c == ';') &&
  3. (j - 1 < here || !Character.isDigit(chs[j - 1 - start])) &&
  4. (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
  5. ((c == '/' || c == '-') &&
  6. (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
  7. (c >= FIRST_CJK && isIdeographic(c, true) &&
  8. j + 1 < next && isIdeographic(chs[j + 1 - start], false))) {
  9. okwidth = w;
  10. ok = j + 1;
  11. if (fittop < oktop)
  12. oktop = fittop;
  13. if (fitascent < okascent)
  14. okascent = fitascent;
  15. if (fitdescent > okdescent)
  16. okdescent = fitdescent;
  17. if (fitbottom > okbottom)
  18. okbottom = fitbottom;
  19. }

去掉就可以了。去掉后标点符号可以显示在行首和行尾,英文单词也可以被分开在两行中显示。

2)自定义View显示文本

网上就有达人采用自定义View来解决这个问题,我做了实验并总结了一下:

自定义View的步骤:

1)继承View类或其子类,例子继承了TextView类;

2)写构造函数,通过XML获取属性(这一步中可以自定义属性,见例程);

3)重写父类的某些函数,一般都是以on开头的函数,例子中重写了onDraw()和onMeasure()函数;

=========================StartCustomTextView.java=============================

[java] view plaincopy
  1. public class StartCustomTextView extends TextView {
  2. public  static  int m_iTextHeight; //文本的高度
  3. public  static  int m_iTextWidth;//文本的宽度
  4. private Paint mPaint = null;
  5. private String string="";
  6. private float LineSpace = 0;//行间距
  7. private int left_Margin;
  8. private int right_Margin;
  9. private int bottom_Margin;
  10. public StartCustomTextView(Context context, AttributeSet set)
  11. {
  12. super(context,set);
  13. DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
  14. TypedArray typedArray = context.obtainStyledAttributes(set, R.styleable.CYTextView);
  15. int width = displayMetrics.widthPixels;
  16. left_Margin = 29;
  17. right_Margin = 29;
  18. bottom_Margin = 29;
  19. width = width - left_Margin -right_Margin;
  20. float textsize = typedArray.getDimension(R.styleable.CYTextView_textSize, 34);
  21. int textcolor = typedArray.getColor(R.styleable.CYTextView_textColor, getResources().getColor(R.color.white));
  22. float linespace = typedArray.getDimension(R.styleable.CYTextView_lineSpacingExtra, 15);
  23. int typeface = typedArray.getColor(R.styleable.CYTextView_typeface, 0);
  24. typedArray.recycle();
  25. //设置 CY TextView的宽度和行间距www.linuxidc.com
  26. m_iTextWidth=width;
  27. LineSpace=linespace;
  28. // 构建paint对象
  29. mPaint = new Paint();
  30. mPaint.setAntiAlias(true);
  31. mPaint.setColor(textcolor);
  32. mPaint.setTextSize(textsize);
  33. switch(typeface){
  34. case 0:
  35. mPaint.setTypeface(Typeface.DEFAULT);
  36. break;
  37. case 1:
  38. mPaint.setTypeface(Typeface.SANS_SERIF);
  39. break;
  40. case 2:
  41. mPaint.setTypeface(Typeface.SERIF);
  42. break;
  43. case 3:
  44. mPaint.setTypeface(Typeface.MONOSPACE);
  45. break;
  46. default:
  47. mPaint.setTypeface(Typeface.DEFAULT);
  48. break;
  49. }
  50. }
  51. @Override
  52. protected void onDraw(Canvas canvas)
  53. {
  54. super.onDraw(canvas);
  55. char ch;
  56. int w = 0;
  57. int istart = 0;
  58. int m_iFontHeight;
  59. int m_iRealLine=0;
  60. int x=2;
  61. int y=30;
  62. Vector   m_String=new Vector();
  63. FontMetrics fm = mPaint.getFontMetrics();
  64. m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;//计算字体高度(字体高度+行间距)
  65. for (int i = 0; i < string.length(); i++)
  66. {
  67. ch = string.charAt(i);
  68. float[] widths = new float[1];
  69. String srt = String.valueOf(ch);
  70. mPaint.getTextWidths(srt, widths);
  71. if (ch == '\n'){
  72. m_iRealLine++;
  73. m_String.addElement(string.substring(istart, i));
  74. istart = i + 1;
  75. w = 0;
  76. }else{
  77. w += (int) (Math.ceil(widths[0]));
  78. if (w > m_iTextWidth){
  79. m_iRealLine++;
  80. m_String.addElement(string.substring(istart, i));
  81. istart = i;
  82. i--;
  83. w = 0;
  84. }else{
  85. if (i == (string.length() - 1)){
  86. m_iRealLine++;
  87. m_String.addElement(string.substring(istart, string.length()));
  88. }
  89. }
  90. }
  91. }
  92. m_iTextHeight=m_iRealLine*m_iFontHeight+2;
  93. canvas.setViewport(m_iTextWidth, m_iTextWidth);
  94. for (int i = 0, j = 0; i < m_iRealLine; i++, j++)
  95. {
  96. canvas.drawText((String)(m_String.elementAt(i)), x,  y+m_iFontHeight * j, mPaint);
  97. }
  98. }
  99. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  100. {
  101. int measuredHeight = measureHeight(heightMeasureSpec);
  102. int measuredWidth = measureWidth(widthMeasureSpec);
  103. this.setMeasuredDimension(measuredWidth, measuredHeight);
  104. LayoutParams layout = new LinearLayout.LayoutParams(measuredWidth,measuredHeight);
  105. layout.leftMargin= left_Margin;
  106. layout.rightMargin= right_Margin;
  107. layout.bottomMargin= bottom_Margin;
  108. this.setLayoutParams(layout);
  109. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  110. }
  111. private int measureHeight(int measureSpec)
  112. {
  113. int specMode = MeasureSpec.getMode(measureSpec);
  114. int specSize = MeasureSpec.getSize(measureSpec);
  115. // Default size if no limits are specified.
  116. initHeight();
  117. int result = m_iTextHeight;
  118. if (specMode == MeasureSpec.AT_MOST){
  119. // Calculate the ideal size of your
  120. // control within this maximum size.
  121. // If your control fills the available
  122. // space return the outer bound.
  123. result = specSize;
  124. }else if (specMode == MeasureSpec.EXACTLY){
  125. // If your control can fit within these bounds return that value.
  126. //            result = specSize;
  127. }
  128. return result;
  129. }
  130. private void initHeight()
  131. {
  132. //设置 CY TextView的初始高度为0
  133. m_iTextHeight=0;
  134. //大概计算 CY TextView所需高度
  135. FontMetrics fm = mPaint.getFontMetrics();
  136. int m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;
  137. int line=0;
  138. int istart=0;
  139. int w=0;
  140. for (int i = 0; i < string.length(); i++)
  141. {
  142. char ch = string.charAt(i);
  143. float[] widths = new float[1];
  144. String srt = String.valueOf(ch);
  145. mPaint.getTextWidths(srt, widths);
  146. if (ch == '\n'){
  147. line++;
  148. istart = i + 1;
  149. w = 0;
  150. }else{
  151. w += (int) (Math.ceil(widths[0]));
  152. if (w > m_iTextWidth){
  153. line++;
  154. istart = i;
  155. i--;
  156. w = 0;
  157. }else{
  158. if (i == (string.length() - 1)){
  159. line++;
  160. }
  161. }
  162. }
  163. }
  164. m_iTextHeight=(line)*m_iFontHeight+2;
  165. }
  166. private int measureWidth(int measureSpec)
  167. {
  168. int specMode = MeasureSpec.getMode(measureSpec);
  169. int specSize = MeasureSpec.getSize(measureSpec);
  170. // Default size if no limits are specified.
  171. int result = 500;
  172. if (specMode == MeasureSpec.AT_MOST){
  173. // Calculate the ideal size of your control
  174. // within this maximum size.
  175. // If your control fills the available space
  176. // return the outer bound.
  177. result = specSize;
  178. }else if (specMode == MeasureSpec.EXACTLY){
  179. // If your control can fit within these bounds return that value.
  180. result = specSize;
  181. }
  182. return result;
  183. }
  184. public void SetText(String text)
  185. {
  186. string = text;
  187. // requestLayout();
  188. // invalidate();
  189. }
  190. }

=======================attrs.xml===============================

该文件是自定义的属性,放在工程的res/values下

[html] view plaincopy
  1. <resources>
  2. <attr name="textwidth" format="integer"/>
  3. <attr name="typeface">
  4. <enum name="normal" value="0"/>
  5. <enum name="sans" value="1"/>
  6. <enum name="serif" value="2"/>
  7. <enum name="monospace" value="3"/>
  8. </attr>
  9. <declare-styleable name="CYTextView">
  10. <attr name="textwidth" />
  11. <attr name="textSize" format="dimension"/>
  12. <attr name="textColor" format="reference|color"/>
  13. <attr name="lineSpacingExtra" format="dimension"/>
  14. <attr name="typeface" />
  15. </declare-styleable>
  16. </resources>

=======================main.xml==========================

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <ScrollView
  3. xmlns:Android="http://schemas.android.com/apk/res/android"
  4. Android:layout_width="320px"
  5. Android:layout_height="320px"
  6. Android:background="#ffffffff"
  7. >
  8. <LinearLayout
  9. xmlns:Android="http://schemas.android.com/apk/res/android"
  10. Android:orientation="vertical"
  11. Android:layout_width="fill_parent"
  12. Android:layout_height="fill_parent">
  13. <com.cy.CYTextView.CYTextView
  14. xmlns:cy="http://schemas.Android.com/apk/res/ com.cy.CYTextView "
  15. Android:id="@+id/mv"
  16. Android:layout_height="wrap_content"
  17. Android:layout_width="wrap_content"
  18. cy :textwidth="320"
  19. cy :textSize="24sp"
  20. cy :textColor="#aa000000"
  21. cy :lineSpacingExtra="15sp"
  22. cy :typeface="serif">
  23. </com. cy .CYTextView.CYTextView>
  24. </LinearLayout>
  25. </ScrollView>

蓝色代码即为自定义View,其中以cy命名空间开头的属性是自定义属性;

=======================Main.java=============================

[java] view plaincopy
  1. public class Main extends Activity {
  2. CYTextView mCYTextView;
  3. String text = "Android提供了精巧和有力的组件化模型构建用户的UI部分。主要是基于布局类:View和 ViewGroup。在此基础上,android平台提供了大量的预制的View和xxxViewGroup子 类,即布局(layout)和窗口小部件(widget)。可以用它们构建自己的UI。";
  4. /** Called when the activity is first created. */
  5. @Override
  6. public void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. this.setContentView(R.layout.main);
  9. mCYTextView = (CYTextView)findViewById(R.id.mv);
  10. mCYTextView.SetText(text);
  11. }
  12. }

转自:http://hi.baidu.com/java_rose/blog/item/2940a030d1ec7f3e96ddd847.html

另外一个人的自定义TextView,学习一下

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

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

 1 package cc.snser.test;
 2
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5
 6 public class TestCActivity extends Activity {
 7     private AutoSplitTextView mText;
 8
 9     @Override
10     protected void onCreate(Bundle savedInstanceState) {
11         super.onCreate(savedInstanceState);
12
13         setContentView(R.layout.testc);
14
15         mText = (AutoSplitTextView)findViewById(R.id.txt);
16         mText.setText("本文地址http://www.cnblogs.com/goagent/p/5159125.html本文地址啊本文。地址。啊http://www.cnblogs.com/goagent/p/5159125.html");
17     }
18 }

 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
 8     <cc.snser.test.AutoSplitTextView
 9         android:id="@+id/txt"
10         android:layout_width="match_parent"
11         android:layout_height="200dp"
12         android:layout_marginTop="11dp"
13         android:layout_marginLeft="11dp"
14         android:layout_marginRight="11dp"
15         android:background="@android:color/holo_blue_light"
16         android:textSize="20sp"
17         android:textColor="@android:color/black" />
18
19 </LinearLayout>

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/snser/p/5159125.html]

TextView的自动换行问题相关推荐

  1. android textview 关闭自动换行,Android TextView停止换行

    我花了很多时间寻找解决方案,但是没有发现任何与我所遇到的相似的东西.当我在G2上运行我的应用程序时,我的所有textview都不会换行.(不管视图有多大.)如果我在模拟器上运行,它们会自动换行.部署到 ...

  2. 基于LinearLayout的小标签(TextView)自动换行(修改)

    设计最初是因为公司项目需要多处显示多个小标签,并且需要多行展示,最开始使用的GridLayout,但是这个网格布局局限性太高,标签是动态的,内容也不定,用GridLayout就会有多行占用的各种显示问 ...

  3. TextView 判断自动换行

    先看 需求: 布局中有四种样式 (标签必须在一起 不能截断) 因为没办法用字段区分这四种类型, 所以只能用一个item布局实现效果 原理是这样的, 主要是中间的内容 跟后面的标签 会出现这样的问题, ...

  4. Android TextView 实现一个单词分两行显示

    今天遇到一个需求,TextView实现自动换行时一个英文单词能够换行显示,使布局整齐.通过网上查询,确定实现逻辑如下: 自定义TextView,重写其onMeasure方法,在测量textView的宽 ...

  5. JustifyTextView 解决TextView中英文混排自动换行的问题

    最近在做着一个项目,里边会显示很长的一段文字,但是这些文字并不会整齐地排列,遇到文字中带有中英文时,果断给我换行了,好无语..接着就是不断地百度百度,找到了一堆一两年前的东西,不是叫你半角转全角,就是 ...

  6. 解决TextView排版混乱或者自动换行的问题

    解决TextView排版混乱或者自动换行的问题 参考文章: (1)解决TextView排版混乱或者自动换行的问题 (2)https://www.cnblogs.com/android-blogs/p/ ...

  7. TextView设置文字包含中英文时自动换行问题的终极解决方案

    TextView设置文字包含中英文时自动换行问题的终极解决方案 参考文章: (1)TextView设置文字包含中英文时自动换行问题的终极解决方案 (2)https://www.cnblogs.com/ ...

  8. TextView文本尾部添加标签,支持自动换行

    文章目录 TextView文本尾部添加标签,支持自动换行 需求 使用SpannableStringBuilder + ImageSpan实现 代码实现 参考 TextView文本尾部添加标签,支持自动 ...

  9. TextView解决中英文混排自动换行

    自定义TextView解决中英文混排自动换行的问题 Textview中设置中英文混合格式的字符串时会自动换行,本文就是解决这个问题的办法,废话不多说直接上代码 点击查看原文: 代码 import an ...

最新文章

  1. matlab矩阵方块网络着色imshow_matlab中用imshow()显示图像与图像矩阵的数据类型的关系...
  2. 数论-朴素卢卡斯(Lucas)模板
  3. SAP OData的CSRF token在ABAP Netweaver服务器上是怎么生成的
  4. 浅谈C/C++中的指针和数组(一)
  5. flutter怎么添加ios网络权限_使用Flutter控制蓝牙通讯
  6. tensorflow 的版本差异与变化
  7. Asp.Net Web API(一)
  8. java坦克大战墙_坦克大战 - java代码库 - 云代码
  9. k近邻matlab,模式识别 最近邻法和k近邻法MATLAB实现.doc
  10. 追踪服务器的网站,网站Tracert路由追踪|在线Tracert工具—卡卡网 www.webkaka.com
  11. python defaultdict
  12. 计算机视觉 开源_年轻的计算机科学家分享了她的开源故事
  13. 从作者的角度去阅读一本书-一种全新的阅读体验
  14. 【基础】Flink -- DataStream API
  15. 超实用的8款Chrome插件
  16. python小工具-批量压缩图片
  17. 瓜子二手车后台研发实习生面经
  18. QGIS教程-2:数据的加载
  19. iis 设置网站前台后台 http和https分离访问
  20. Python操作PC客户端之自动化实现原理(pywinauto)

热门文章

  1. 文献管理器真的太难用了——文献管理、笔记和参考文献生成引用的高效方法——不完全记录
  2. [Python]指定搜索关键字,通过网页获取bilibili的相关视频信息
  3. linux基本面试题
  4. Qt安装包和更新器使用镜像源加速(两种方法)
  5. Linux下的SQL查询只显示结果,SQL查询语句精华文章(转)
  6. Java编程定义一个数组,输出数组中的最大值与最小值
  7. Java的语法结构和数组
  8. 小米计算机无法清除,小米手机开不了机,清除不了数据,现无电脑,请问我该怎么做...
  9. KKB:JSON解析
  10. 李佳琦与薇娅直播间竞品分析(求意见)