開發過程當中咱們常常會遇到文字尾部添加標籤的需求,看是很簡單,其實蠻難作的。好比咱們的設計稿以下:java
打眼一看,一個水平方向線性佈局就解決了,內部寫兩個TextView就行。android
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="20dp">
<TextView
android:id="@+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="天行健,君子以自強不息;"
android:textColor="#000"
android:textSize="15sp" />
<TextView
android:id="@+id/tv4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/room_member_role_bg"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:text="王蛋蛋的芭比"
android:textColor="#000"
android:textSize="15sp" />
</LinearLayout>
複製代碼
emmmmm,可是,要是文字是多行的呢,咱們的標籤還能順利的放在後面麼?git
若是第一行文本過長,咱們就會獲得下面的結果: 尾部標籤顯示不全:github
或者以下,尾部標籤直接不顯示。緩存
若是文字最後一行的剩餘空間放不下咱們的尾部標籤,比較通用的作法是讓標籤換行。bash
咱們想要的是這樣的:app
接下來咱們一步步實現這個需求。佈局
使用過SpannableStringBuilder的同窗都驚歎於它的強大,經過SpannableStringBuilder#setSpan()
咱們能夠給TextView的文本設置獨特的樣式,好比加粗、斜體、字體大小、字體顏色、背景顏色、圖片、刪除線、下劃線、點擊事件等等。字體
咱們這裏也使用SpannableStringBuilder + 特定Span
的方式來實現。ui
咱們的尾部標籤實質上是給特定文本添加一個drawable背景
,通過調研發現,雖然咱們能夠經過ReplacementSpan
等方式給文字繪製drawable背景,可是背景上方的文字卻不顯示,這個方案就暫時夭折了。
回過頭來,咱們發現SpannableStringBuilder + ImageSpan
能夠實現將圖片自動換行,而且若是剩餘空間不足時圖片會自動換行,以下所示:
從第二個TextView能夠看出,當前行的剩餘空間不夠放置ImageSpan
圖片時,會自動換行。這樣就解決了咱們的自動換行的問題。
咱們接下來看下ImageSpan的構造方法,會發現它不只支持Drawable,還支持Bitmap對象,具體以下:
咱們還知道,View有個getDrawingCache()
方法,它能夠生成當前View的Bitmap緩存。
此時咱們的實現思路能夠串起來了,具體以下圖:
具體分爲四步: ①建立TextView對象,設置drawable背景,設置字體樣式,設置間距,設置文本等 ②將View生成Bitmap對象 ③根據Bitmap對象生成ImageSpan對象 ④將ImageSpan對象設置到SpannableStringBuilder的對應位置
具體代碼以下:註釋寫的很清楚,這裏就再也不贅述。
private void addTagToTextView(TextView target, String title, String tag) {
if (TextUtils.isEmpty(title)) {
title = "";
}
String content = title + tag;
/**
* 建立TextView對象,設置drawable背景,設置字體樣式,設置間距,設置文本等
* 這裏咱們爲了給TextView設置margin,給其添加了一個父容器LinearLayout。不過他倆都只是new出來的,不會添加進任何佈局
*/
LinearLayout layout = new LinearLayout(this);
TextView textView = new TextView(this);
textView.setText(tag);
textView.setBackground(getResources().getDrawable(R.drawable.room_member_role_bg));
textView.setTextSize(12);
textView.setTextColor(Color.parseColor("#FDA413"));
textView.setIncludeFontPadding(false);
textView.setPadding(ScreenUtils.dip2px(this, 6), 0,
ScreenUtils.dip2px(this, 6), 0);
textView.setHeight(ScreenUtils.dip2px(this, 17));
textView.setGravity(Gravity.CENTER_VERTICAL);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// 設置左間距
layoutParams.leftMargin = ScreenUtils.dip2px(this, 6);
// 設置下間距,簡單解決ImageSpan和文本豎直方向對齊的問題
layoutParams.bottomMargin = ScreenUtils.dip2px(this, 3);
layout.addView(textView, layoutParams);
/**
* 第二步,測量,繪製layout,生成對應的bitmap對象
*/
layout.setDrawingCacheEnabled(true);
layout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
// 給上方設置的margin留出空間
layout.layout(0, 0, textView.getMeasuredWidth() + ScreenUtils.dip2px(this, (6 + 3)), textView.getMeasuredHeight());
// 獲取bitmap對象
Bitmap bitmap = Bitmap.createBitmap(layout.getDrawingCache());
//千萬別忘最後一步
layout.destroyDrawingCache();
/**
* 第三步,經過bitmap生成咱們須要的ImageSpan對象
*/
ImageSpan imageSpan = new ImageSpan(this, bitmap);
/**
* 第四步將ImageSpan對象設置到SpannableStringBuilder的對應位置
*/
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
//將尾部tag字符用ImageSpan替換
ssb.setSpan(imageSpan, title.length(), content.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
target.setText(ssb);
}
複製代碼
項目地址:Android_Base_Demo
具體代碼請看:SpannableStringBuilderActivity
頁面入口展現:
固然了,實現這種需求的方式有不少種,這裏的這種方式比較取巧。你們若是有好的實現方式,還望不吝賜教,比心。