最近公司做一個社區(qū)類的應(yīng)用赃泡,發(fā)現(xiàn)android項目中的文字排版參差不齊的情況非常嚴(yán)重来农,不得不想辦法解決一下鞋真。由于之前只做過處理簡單文本的這種問題崇堰,沒加上含有表情沃于、內(nèi)鏈等處理,由于網(wǎng)上的各種處理辦法達(dá)到的效果并不是很滿易海诲,所以只好重寫來解決這個問題繁莹。
看過源碼的都知道TextView里面處理換行都是在Layout里面,一般來說換行是由于英文字符及數(shù)字導(dǎo)致的特幔,ellipsize則是由于計算的長度而導(dǎo)致...后面會顯示半個字咨演,這是android本身的一個BUG,所以經(jīng)過研究找到了里面計算字符長度的方法<font color=#0099ff>Layout.getDesiredWidth</font>蚯斯,方法的英文大略意思是:返回一個指定文本的寬度<font color=#ff0000>(英文略渣)</font>
由于里面的計算是用for循環(huán)計算每個CharSequence的長度,所以直接用反射通過measurePara方法來獲取寬度并判斷是否達(dá)到TextView的Width
onMeasure
if(mPostContentBean != null && !mPostContentBean.mParsed){
mBuilder.clear();
if(getWidth() != 0){
try {
int contentLength = getWidth() - getPaddingLeft() - getPaddingRight();
int length = getText().length();
int lines = 0;
int start = 0;
for (int i = 0; i < length; i++) {
int end = TextUtils.indexOf(getText(), '\n', i, length);
if (end < 0)
i = length;
else
i = end + 1;
for (int j = start; j <= i; j++) {
CharSequence sequence = getText().subSequence(start, j);
mTmepBuilder.clear();
mTmepBuilder.append(sequence);
if(mMaxLines == lines + 1){
mTmepBuilder.append(mEllipsize);
}
float w = measurePara(mTmepBuilder);
if (w > contentLength || j == i){
if(w > contentLength){
j--;
}
end = sequence.length() - 1;
if(j == i){
end = sequence.length();
}
lines++;
start = j;
mBuilder.append(sequence.subSequence(0, end));
if(mMaxLines == lines){
i = length;
j = i;
mBuilder.append(mEllipsize);
}
if(j != length && mBuilder.charAt(mBuilder.length() - 1) != '\n'){
mBuilder.append("\n");
}
}
}
}
mPostContentBean.mParsed = true;
mPostContentBean.mBuilder.clear();
mPostContentBean.mBuilder.append(mBuilder);
setText(mBuilder);
} catch (Exception e) {
e.printStackTrace();
}
}
}
measurePara(SDK16以上的API是不同的)
private float measurePara(CharSequence sequence) throws Exception{
if(android.os.Build.VERSION.SDK_INT < 16){
Method measurePara = Layout.class.getDeclaredMethod("measurePara", TextPaint.class, CharSequence.class, int.class, int.class);
measurePara.setAccessible(true);
return (Float) measurePara.invoke(null, getPaint(), mPaint, sequence, 0, sequence.length());
}else{
Method measurePara = Layout.class.getDeclaredMethod("measurePara", TextPaint.class, CharSequence.class, int.class, int.class);
measurePara.setAccessible(true);
return (Float) measurePara.invoke(null, getPaint(), sequence, 0, sequence.length());
}
}