最近在專案中需要在某個多行英文文字末尾增加一個圖片,嘗試了很多方法,最後用了一個比較Tricky的方法解決了,當然這種方法不一定是最好最優的解決辦法,記錄一下。
問題
如果直接使用drawableRight或者drawableEnd來將圖片放置到文字末尾,結果會是這樣:
圖片會在TextView右邊豎直方向的中間位置顯示,而不是我們期望的在最後一行位置顯示。
這時我們可以嘗試使用ImageSpan來將圖片放置在最後一行:
final TextView text = findViewById(R.id.text);
final String string = "dkffkdjkfjdkfjkdjfdjfkjdkfjkdjkdjfkjdkjk";
//建立一個SpannableString物件,後面增加空格是預留給圖片的
SpannableString spannableString = new SpannableString(string + " ");
//建立圖片的Drawable物件
Drawable drawable = getResources().getDrawable(R.mipmap.copy);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
//建立圖片的ImageSpan物件
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
//設定ImageSpan,將其位置設定在spannableString最後面,起始位置start=spannableString.length() - 1,結束位置為end=spannableString.length(),
// SPAN_INCLUSIVE_EXCLUSIVE表示包含start不包含end
spannableString.setSpan(imageSpan, spannableString.length() - 1, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
text.setText(spannableString);
複製程式碼
效果如下:
圖片確實是放在了最後面,但是英文文字的顯示出現了凌亂。
原因
實際上最後的效果是TextView繪製出來的,原因當然是TextView繪製咯。TextView的Span繪製主要是使用DynamicLayout裡面的方法來計算行數,
呼叫其draw方法(DynamicLayout父類Layout實現)完成繪製。具體實現細節這裡就不在闡述,有興趣的朋友可以自行研究下。
解決
這裡使用了比較討巧的一種方式,問題主要是文字換行並沒有按照我們期望的樣子進行,而是換行之後後面還留了一大半空白。後面發現如果字串中包含了空格的話,
就會自動以空格的位置進行換行。所以解決思路就是按照TextView的寬度,計算每一行能夠容納的字元個數,在每一行的最後插入一個空格,就能解決換行凌亂了。
具體實現如下:
//先設定原始文字
text.setText(string);
//使用post方法,在TextView完成繪製流程後在訊息佇列中被呼叫
text.post(new Runnable() {
@Override
public void run() {
//獲取第一行的寬度
float lineWidth = text.getLayout().getLineWidth(0);
//獲取第一行最後一個字元的下標
int lineEnd = text.getLayout().getLineEnd(0);
//計算每個字元佔的寬度
float widthPerChar = lineWidth / (lineEnd + 1);
//計算TextView一行能夠放下多少個字元
int numberPerLine = (int) Math.floor(text.getWidth() / widthPerChar);
//在原始字串中插入一個空格,插入的位置為numberPerLine - 1
StringBuilder stringBuilder = new StringBuilder(string).insert(numberPerLine - 1, " ");
//SpannableString的構建
SpannableString spannableString = new SpannableString(stringBuilder.toString() + " ");
Drawable drawable = getResources().getDrawable(R.mipmap.copy);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
spannableString.setSpan(imageSpan, spannableString.length() - 1, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
text.setText(spannableString);
}
});
複製程式碼
這裡使用的是post方法延後處理,當然也可以使用ViewTreeObserver監聽佈局完成再進行處理,最後的效果,完美: