編輯:關於android開發
一、問題在哪裡?
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,直接包含自動排版換行的功能:



4.2 實現懸掛縮進

調用方式:
autoSplitText(tv, "1、");
懸掛縮進效果:

[轉載請保留本文地址:http://www.cnblogs.com/goagent/p/5159125.html]
Android提高21篇之十九:“多方向”抽屜
在android上要實現類似Launch的抽屜效果,大家一定首先會想起SlidingDrawer。
如何正確配置Nginx+PHP
如何正確配置Nginx+PHP導讀對很多人而言,配置Nginx+PHP無外乎就是搜索一篇教程,然後拷貝粘貼。聽上去似乎也沒什麼問題,可惜實際上網絡上很多資料本身年久失修,
Android_LIFE幫(基於最新百度地圖API的開源項目)
Android_LIFE幫(基於最新百度地圖API的開源項目) 越來越多的APP用到了地圖API,所以本人依賴百度地圖提供的API做了一個簡單的項目,希望大家多多支持和s
Android AutoLayout全新的適配方式 堪稱適配終結者
Android AutoLayout全新的適配方式 堪稱適配終結者 一、概述 相信Android的開發者對於設配問題都比較苦惱,Google官方雖