編輯:關於Android編程
一、介紹

這是新浪微博的一個帖子,剛好包括了話題、表情、@好友三種顯示。顯示方法上篇已經闡述了,就是使用SpannableString。這篇主要介紹顯示這種帖子的解析工具類。
二、實現
1.字符串表示和對應正則表達式
話題用##號括起來
表情用[]表示
@好友昵稱
借助正則匹配來解析帖子信息。
話題 -> #[^#]+#
表情 -> [[^]]+]
@好友 -> @好友昵稱
2.寫一個通用方法,對spanableString進行正則判斷,如果符合要求,則將內容變色
private static void dealPattern(int color, SpannableString spannableString, Pattern patten, int start) throws Exception {
Matcher matcher = patten.matcher(spannableString);
while (matcher.find()) {
String key = matcher.group();
// 返回第一個字符的索引的文本匹配整個正則表達式,ture 則繼續遞歸
if (matcher.start() < start) {
continue;
}
// 計算該內容的長度,也就是要替換的字符串的長度
int end = matcher.start() + key.length();
//設置前景色span
spannableString.setSpan(new ForegroundColorSpan(color), matcher.start(), end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
if (end < spannableString.length()) {
// 如果整個字符串還未驗證完,則繼續。。
dealPattern(color, spannableString, patten, end);
}
break;
}
}
3.應為有些是可點擊的,所以需要一個方法來處理可點擊的內容
①先定義一個接口,通過接口的方式將點擊事件交給調用者
public interface SpanClickListener<T>{
void onSpanClick(T t);
}
②寫一個通用方法,對spanableString進行正則判斷,如果符合要求,將內容設置可點擊
private static void dealClick(SpannableString spannableString, Pattern patten, int start, final SpanClickListener spanClickListener, final Object bean){
Matcher matcher = patten.matcher(spannableString);
while (matcher.find()) {
String key = matcher.group();
// 返回第一個字符的索引的文本匹配整個正則表達式,ture 則繼續遞歸
if (matcher.start() < start) {
continue;
}
// 計算該內容的長度,也就是要替換的字符串的長度
int end = matcher.start() + key.length();
spannableString.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
spanClickListener.onSpanClick(bean);
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
//設置畫筆屬性
ds.setUnderlineText(false);//默認有下劃線
}
}, matcher.start(), end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
if (end < spannableString.length()) {
// 如果整個字符串還未驗證完,則繼續。。
dealClick(spannableString, patten, end, spanClickListener, bean);
}
break;
}
}
4.表情解析方法(後面會寫一篇關於表情的處理)
private void dealExpression(Context context,
SpannableString spannableString, Pattern patten, int start)
throws Exception {
Matcher matcher = patten.matcher(spannableString);
while (matcher.find()) {
String key = matcher.group();
if (matcher.start() < start) {
continue;
}
String value = emojiMap.get(key);
if (TextUtils.isEmpty(value)) {
continue;
}
// 通過上面匹配得到的字符串來生成圖片資源id
int resId = context.getResources().getIdentifier(value, "drawable",
context.getPackageName());
if (resId != 0) {
Drawable emoji = context.getResources().getDrawable(resId);
int w = (int) (emoji.getIntrinsicWidth() * 0.40);
int h = (int) (emoji.getIntrinsicHeight() * 0.40);
emoji.setBounds(0, 0, w, h);
// 通過圖片資源id來得到bitmap,用一個ImageSpan來包裝
ImageSpan imageSpan = new ImageSpan(emoji);
// 計算該圖片名字的長度,也就是要替換的字符串的長度
int end = matcher.start() + key.length();
// 將該圖片替換字符串中規定的位置中
spannableString.setSpan(imageSpan, matcher.start(), end,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
if (end < spannableString.length()) {
dealExpression(context, spannableString, patten, end);
}
break;
}
}
}
5.關鍵詞變色處理方法,這個實際中的使用場景比如地圖關鍵字搜索,匹配到關鍵字的地址中關鍵字顯示特別顏色
public static SpannableString getKeyWordSpan(int color, String str, String patterStr) throws Exception {
SpannableString spannableString = new SpannableString(str);
Pattern patten = Pattern.compile(patterStr, Pattern.CASE_INSENSITIVE);
dealPattern(color, spannableString, patten, 0);
return spannableString;
}
6.話題處理,參數中需要傳入話題對象。這裡只處理了一個帖子中只有一個話題的情況
public static SpannableString getTopicSpan(int color, String str, boolean clickable,SpanClickListener spanClickListener, Topic topic) throws Exception {
SpannableString spannableString = new SpannableString(str);
Pattern patten = Pattern.compile(PatternString.TOPIC_PATTERN, Pattern.CASE_INSENSITIVE);
if(clickable){
dealClick(spannableString, patten, 0, spanClickListener, topic);
}
dealPattern(color, spannableString, patten, 0);
return spannableString;
}
7.@好友處理,參數中需要傳入@的好友列表
public static SpannableString getAtUserSpan(int color, String str, boolean clickable, SpanClickListener spanClickListener, List<User> atUsers) throws Exception {
SpannableString spannableString = new SpannableString(str);
Pattern patten;
for (User u : atUsers) {
patten = Pattern.compile("@" + u.getName(), Pattern.CASE_INSENSITIVE);
if(clickable){
dealClick(spannableString, patten, 0, spanClickListener, u);
}
dealPattern(color, spannableString, patten, 0);
}
return spannableString;
}
8.表情處理,就這麼簡潔
public static SpannableString getExpressionSpan(Context context, String str) throws Exception {
return ExpressionConvertUtil.getInstace().getExpressionString(context, str);
}
三、使用
1.關鍵字變色
private void testColoredKeywd() {
String string = "Android一詞的本義指“機器人”,同時也是Google於2007年11月5日,Android logo相關圖片,Android logo相關圖片(36張)\n";
SpannableString cardText = null;
try {
cardText = SpanUtils.getKeyWordSpan(getResources().getColor(R.color.md_green_600), string, "Android");
} catch (Exception e) {
e.printStackTrace();
}
tvColoredKeywd.setText(cardText);
}
2.話題測試,需要注意的是,讓部分內容可點擊需要設置tvTopic.setMovementMethod(LinkMovementMethod.getInstance());,否則點擊無效果
private void testTopic() {
String topic = "#舌尖上的大連#四種金牌烤芝士吃法愛吃芝士的盆友不要錯過了~L秒拍視頻\n";
SpannableString topicText = null;
try {
topicText = SpanUtils.getTopicSpan(Color.BLUE, topic, true, new SpanUtils.SpanClickListener<Topic>() {
@Override
public void onSpanClick(Topic t) {
Toast.makeText(MainActivity.this, "點擊話題:" + t.toString() , Toast.LENGTH_SHORT).show();
}
}, new Topic(1, "舌尖上的大連"));
} catch (Exception e) {
e.printStackTrace();
}
tvTopic.setText(topicText);
//如果想實現點擊,必須要設置這個
tvTopic.setMovementMethod(LinkMovementMethod.getInstance());
}
3.@好友測試
private void textAtUsers(){
List<User> users = new ArrayList<>();
users.add(new User(1, "好友1"));
users.add(new User(2, "好友2"));
StringBuilder sb = new StringBuilder("快來看看啊");
for (User u : users) {
sb.append("@").append(u.getName());
}
sb.append("\n");
try {
SpannableString atSpan = SpanUtils.getAtUserSpan(Color.BLUE, sb.toString(), true, new SpanUtils.SpanClickListener<User>() {
@Override
public void onSpanClick(User user) {
Toast.makeText(MainActivity.this, "@好友:" + user.toString(), Toast.LENGTH_SHORT).show();
}
}, users);
tvTestAt.setText(atSpan);
tvTestAt.setMovementMethod(LinkMovementMethod.getInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
4.表情測試
private void textExpression(){
String exStr = "今天天氣很好啊[呲牙],是不是應該做點什麼[色]";
SpannableString span = null;
try {
span = SpanUtils.getExpressionSpan(this, exStr);
} catch (Exception e) {
e.printStackTrace();
}
tvExpression.setText(span);
}
效果圖

下載:https://github.com/LineChen/SpannableStringDemo
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
Android圓形頭像圖Circle ImageView
《Android圓形頭像圖Circle ImageView》需要處理的原始圖(pic): 使用CircleImageView處理後的圖(作為頭像):
Android入門——構建UI布局的多種方式
引言作為Android App,給人第一印象的就是用戶界面(UI),簡潔友好的UI,自然會給用戶優秀的體驗,自然很容易就得到用戶的認可和贊許,這樣App才變得真正的有價值
Andorid之GreenDao
第一步是配置:在gradle下配置apply plugin: 'com.android.application'android { compileS
Android PullToZoomListView實現放大回彈效果
版本:1.0 日期:2014.8.4版權:© 2014 kince 轉載注明出處 之前看過一篇文章,鏈接是:可以下拉縮放HeaderView的ListView: