Android用戶端富文本
現階段問題
在Android用戶端展現一個普通資料非常的友善,直接調用textview.setText()方法,但是當TextView比較複雜時(例如存在@使用者,##話題,部分字元樣式、網址連結等),普通的TextView就無法完成需求,需要自己封裝一個富文本TextView。
Demo
Coding 冒泡示例
##
分析
1.一個TextView中不同類别的資訊,需要由不同樣式的顯示,一般的用法textview.setTextColor(color)會将所有的文字變成同一種顔色,這顯然是不符合要求的。為了實作這一個需求,我們将會用到SpannableStringBuilder這個類。
預備知識
SpannableStringBuilder:
基本概念
SpannableStringBuilder 和 StringBuilder類似,都可以存儲字元串,不同的是SpannableStringBuilder有一個setSpan()函數,可以給存儲的String添加不同的樣式。如加下劃線、背景色、字型顔色、字型大小等。
另外需要注意的是,當SpannableStringBuilder中存儲了一個有樣式的String,當把spannableStringBuilder展示在TextView、EditTextView中時,能顯示這些樣式;當展示在canvas上時,因為Canvas不支援SpannableStringBuilder的額外資訊,是以會退化成一個普通的String,不顯示樣式資訊。
setSpan()函數
void setSpan(Object what,int startIndex,int endIndex,int flag);
說明:
參數
說明
Object what
設定Span樣式
int startIndex
樣式開始的Index
int endIndex
樣式結束的Index
int flag
新插入字元的樣式設定
注意點:
endIndex:字型樣式結束的Index,該Index對應的字元不使用樣式,比如有一個字元串為s = “abcd”,s.setSpan(span,0,2,flag),此時第0、1個字元ab使用了樣式span,endIndex對應的字元c不使用。
flag:取值如下
取值
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
前後都不包括,即在指定範圍的前面和後面插入新字元都不會應用新樣式
Spannable.SPAN_EXCLUSIVE_INCLUSIVE
前面不包括,後面包括。即僅在範圍字元的後面插入新字元時會應用新樣式
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
前面包括,後面不包括。
Spannable.SPAN_INCLUSIVE_INCLUSIVE
前後都包括
簡單示例
1
2
3
4
5
6
//設定字型顔色
textview1 = (TextView) findViewById(R.id.text1);
SpannableStringBuilder spannableStringBuilder1 = newSpannableStringBuilder("Android");
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.BLUE);
spannableStringBuilder1.setSpan(foregroundColorSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
textview1.setText(spannableStringBuilder1);
效果:
多種Span
由以上的簡單示例我們可以看出,設定一個樣式的一般步驟是:
構造一個SpannableStringBuilder
構造一個Span,并設定在SpannableStringBuilder上
将SpannableStringBuilder綁定在TextView上展示
設定字型顔色
這個已經在簡單示例中展示
設定字型背景顔色
//設定字型背景顔色
textview2 = (TextView) findViewById(R.id.text2);
SpannableStringBuilder spannableStringBuilder2 = newSpannableStringBuilder("Android");
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.RED);
spannableStringBuilder2.setSpan(backgroundColorSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
textview2.setText(spannableStringBuilder2);
設定字型大小
//設定字型大小
textview3 = (TextView) findViewById(R.id.text3);
SpannableStringBuilder spannableStringBuilder3 = newSpannableStringBuilder("Android");
AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(30);
spannableStringBuilder3.setSpan(absoluteSizeSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
textview3.setText(spannableStringBuilder3);
設定字型
//設定字型(加粗斜體)
textview4 = (TextView) findViewById(R.id.text4);
SpannableStringBuilder spannableStringBuilder4 = newSpannableStringBuilder("Android");
StyleSpan styleSpan = new StyleSpan(Typeface.BOLD_ITALIC);
spannableStringBuilder4.setSpan(styleSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
textview4.setText(spannableStringBuilder4);
設定下劃線
//設定下劃線
textview5 = (TextView) findViewById(R.id.text5);
SpannableStringBuilder spannableStringBuilder5 = newSpannableStringBuilder("Android");
UnderlineSpan underlineSpan = new UnderlineSpan();
spannableStringBuilder5.setSpan(underlineSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
textview5.setText(spannableStringBuilder5);
//設定删除線
textview6 = (TextView) findViewById(R.id.text6);
SpannableStringBuilder spannableStringBuilder6 = newSpannableStringBuilder("Android");
StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
spannableStringBuilder6.setSpan(strikethroughSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
textview6.setText(spannableStringBuilder6);
設定多種樣式
除了設定一個樣式以外,SpannableStringBuilder還支援設定多個樣式。
7
8
9
//設定多種樣式
textview7 = (TextView) findViewById(R.id.text7);
SpannableStringBuilder spannableStringBuilder7 = newSpannableStringBuilder("Android");
spannableStringBuilder7.setSpan(foregroundColorSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
spannableStringBuilder7.setSpan(backgroundColorSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
spannableStringBuilder7.setSpan(underlineSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
spannableStringBuilder7.setSpan(absoluteSizeSpan, 3, 6, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
spannableStringBuilder7.setSpan(strikethroughSpan, 3, 6, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
textview7.setText(spannableStringBuilder7);
點選事件
執行個體代碼
10
11
12
13
14
15
16
17
18
SpannableStringBuilder spannableStringBuilder = newSpannableStringBuilder("Android");
spannableStringBuilder.setSpan(
new ClickableSpan() {
@Override
public void onClick(View widget) {
//do something
}
public void updateDrawState(TextPaint ds) {
//設定一些樣式
//ds.setUnderlineText(false);
//ds.setColor(color);
}, startIndex, endIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
簡單實作
以Listview為例,我們需要實作的是每一個Item和Adapter中的getView()函數。
布局檔案
19
20
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
android:layout_marginTop="16dp"
android:layout_marginLeft="16dp"
android:id="@+id/userhead"/>
<TextView
android:layout_width="match_parent"
android:layout_marginLeft="8dp"
android:layout_marginRight="16dp"
android:layout_toRightOf="@id/userhead"
android:id="@+id/content"/>
</RelativeLayout>
ImageView表示該Item的釋出人,和富文本沒有關系,在Demo中直接寫死資料。
主要内容在TextView中
因為每一個TextView中可能有多個不同樣式的文本(#話題#,@其他使用者,文本内容等),是以先封裝一個文本類:
public class TextObject {
private int mStartIndex;//樣式的開始字元
private int mEndIndex;//結束字元
//private SpannableStringBuilder mSpannableStringBuilder;
private String content;//文本内容
private int mOptionType;//操作符
private int color;//字型顔色
private boolean isUnderline;//是否有下劃線
//...其他需要的屬性可繼承TextObject自行添加
}
這個類封裝的是一個Item中的某一個文本樣式,是以我們還需要封裝一個Item中的文本類:
public class Content {
private List<TextObject> mList;
private SpannableStringBuilder mSpannableStringBuilder;
這個類中有一個List成員變量,存放着該Item中所有的樣式文本。
對于成員變量SpannableStringBuilder,有一個init函數,用于根據List中的TextObject拼接StringBuilder
//拼接SpannableStringBuilder
public void initStringBuilder(){
SpannableStringBuilder spannableStringBuilder = newSpannableStringBuilder();
for (int i = 0;i<mList.size();i++){
spannableStringBuilder.append(mList.get(i).getContent());
}
setmSpannableStringBuilder(spannableStringBuilder);
}
到現在,資料準備工作已經全部完成,現在就要顯示這些資料了。
getView()函數
getview函數中就可以通過content.getSpannableStringBuilder()函數擷取到正文内容,然後即可根據上面的預備知識對其進行設定不同的樣式和點選事件。
設定完成後,需要調用
viewHolder.textview.setMovementMethod(LinkMovementMethod.getInstance());
使其響應點選事件。
Demo效果:
Demo位址
<a href="https://github.com/basti-shi031/RichTextView">Github項目位址</a>
本文轉自 一點點征服 部落格園部落格,原文連結:http://www.cnblogs.com/ldq2016/p/6122393.html,如需轉載請自行聯系原作者