先看下效果圖:
上面是MTextView,下面是默認的TextView。
一、原因
用最簡單的全英文句子為例,如果有一個很長的單詞,這一行剩余的空間顯示不下了,那麼規則就是不打斷單詞,而是把整個單詞丟到下一行開始顯示。這樣本來沒有錯。一是咱們中國人都是方塊字,怎麼都放得下,不存在英文的這個問題。所以不習慣那個排版。二是如果TextView裡面有圖片,如圖,不知道判斷單詞的代碼是怎麼弄得,總之它覺得最後一個啦字和後面的一串表情應該是一個整體,不能分開,就一起丟到第二行了,也就造成了這種難看的排版。要驗證這個說法也很簡單,自己去QQ裡試一試,在每個表情之間都加一個空格,就會發現排版一下子正常了。
二、解決方法
最簡單的就是表情之間加空格,如果不想這麼做,就只有自己來畫啦。
先給初學的朋友解釋一下View繪制的流程,首先是onMeasure(int widthMeasureSpec, int heightMeasureSpec),onMeasure執行的時候,就是父View在問你,小朋友,你要占多大的地兒呀?當然,問你的時候,會給你個限制條件,就是那兩參數,以widthMeasureSpec為例,這參數不能直接用,得先拆開,用int widthMode = MeasureSpec.getMode(widthMeasureSpec) 和 int widthSize =
MeasureSpec.getSize(widthMeasureSpec);widthMode就三種情況:
MeasureSpec.EXACTLY:你就widthSize那麼寬就行了。
MeasureSpec.AT_MOST:你最多只能widthSize那麼寬。
MeasureSpec.UNSPECIFIED:未指定,你愛多寬多寬。
當然,其實這只父View給你的建議,遵不遵守你自己看著辦,但是自己亂來導致顯示不全就不是父View的錯了。
最終你聽取了建議,思量了一番,覺得自己應該有width那麼寬,height那麼高,最後就得用setMeasuredDimension(width, height)這個函數真正確定自己的高寬。然後onMeasure()的工作就完了。
然後就是onDraw(Canvas canvas),這個就簡單了,canvas就是父View給的一塊畫布,愛在上面畫啥都行,比如寫個字drawText(String text,float
x, float y,
Paint paint),
text是要寫的字,paint是寫字的筆,值得注意的是x,y坐標是相對於你自己這一小塊畫布的左上角的。最左上就是0,0右下是width,height
上代碼
/**
* @功能 圖文混排TextView,請使用{@link #setMText(CharSequence)}
* @author huangwei
* @2014年5月27日
* @下午5:29:27
*/
public class MTextView extends TextView
{
private Context context;
/**
* 用於測量字符寬度
*/
private Paint paint = new Paint();
private int textColor = Color.BLACK;
//行距
private float lineSpacing;
private int lineSpacingDP = 2;
// private float lineSpacingMult = 0.5f;
/**
* 最大寬度
*/
private int maxWidth;
/**
* 只有一行時的寬度
*/
private int oneLineWidth = -1;
/**
* 已繪的行中最寬的一行的寬度
*/
private float lineWidthMax = -1;
/**
* 存儲當前文本內容,每個item為一個字符或者一個ImageSpan
*/
private ArrayList
為方便在ListView中使用(ListView反復上下滑動會多次重新onMeasure),加了緩存,相同的情況下可以不用重復在測量一次。
對於SpannableString,只支持了ImageSpan,有其它需要者可自行擴展
Demo:http://download.csdn.net/detail/yellowcath/7421147
或https://github.com/yellowcath/MTextView.git