編輯:關於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,直接包含自動排版換行的功能:
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.xml4.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]
在android上要實現類似Launch的抽屜效果,大家一定首先會想起SlidingDrawer。
如何正確配置Nginx+PHP導讀對很多人而言,配置Nginx+PHP無外乎就是搜索一篇教程,然後拷貝粘貼。聽上去似乎也沒什麼問題,可惜實際上網絡上很多資料本身年久失修,
Android_LIFE幫(基於最新百度地圖API的開源項目) 越來越多的APP用到了地圖API,所以本人依賴百度地圖提供的API做了一個簡單的項目,希望大家多多支持和s
Android AutoLayout全新的適配方式 堪稱適配終結者 一、概述 相信Android的開發者對於設配問題都比較苦惱,Google官方雖