Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> android textview 自動換行 整齊排版,androidtextview

android textview 自動換行 整齊排版,androidtextview

編輯:關於android開發

android textview 自動換行 整齊排版,androidtextview


一、問題在哪裡?

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 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 } View AutoSplitTextView.java 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 } 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 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> 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 //將縮進處理成空格 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 } View Code

調用方式:

 autoSplitText(tv, "1、"); 

懸掛縮進效果:

 [轉載請保留本文地址:http://www.cnblogs.com/goagent/p/5159125.html]

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved