日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android url格式化,Android利用SpannableString实现格式化微博内容

發布時間:2024/7/19 Android 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android url格式化,Android利用SpannableString实现格式化微博内容 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

在Android開發中,有許多信息展示需要通過TextView來展現,如果只是普通的信息展現,使用TextView setText(CharSequence str)設置即可,但是當在TextView里的這段內容需要截取某一部分字段,可以被點擊以及響應響應的操作,這時候就需要用到SpannableString了,SpannableString 配合 TextView 可以輕松實現對特定的文本做特定處理,例如可以修改文字顏色、背景色、將文字替換為圖片實現,點擊效果等。

首先看看最終實現的效果圖:

第一個卡片內的微博是原始文本信息,第二個卡片內的微博是第一個格式化后的文本內容,將微博內的”話題”、”表情”、”網頁鏈接”、以及”@用戶”都進行了處理,并可以點擊,使其和官方微博展示的樣式保持一致。

要實現的效果:

將話題進行變色并且可以點擊提示對應的話題文本內容

將圖片表情替換掉對應的表情關鍵字顯示

將鏈接地址替換成一個鏈接的圖片和”網頁鏈接”四個字顯示

將@的用戶進行變色并且可以點擊提示對應的話題文本內容

需要:

使用正則表達式提取文本內對應的”話題”、”表情”、”網頁鏈接”、以及”@用戶”內容

使用 SpannableString 格式化提取到的文本

給格式化的部分添加點擊事件

定義正則表達式

首先定義”話題”、”表情”、”網頁鏈接”、以及”@用戶”對應的正則表達式和對應的 Pattern。SCHEME 下文會提到具體的用處的。

public class WeiboPattern {

// #話題#

public static final String REGEX_TOPIC = "#[\\p{Print}\\p{InCJKUnifiedIdeographs}&&[^#]]+#";

// [表情]

public static final String REGEX_EMOTION = "\\[(\\S+?)\\]";

// url

public static final String REGEX_URL = "http://[a-zA-Z0-9+&@#/%?=~_\\\\-|!:,\\\\.;]*[a-zA-Z0-9+&@#/%=~_|]";

// @人

public static final String REGEX_AT = "@[\\w\\p{InCJKUnifiedIdeographs}-]{1,26}";

public static final Pattern PATTERN_TOPIC = Pattern.compile(REGEX_TOPIC);

public static final Pattern PATTERN_EMOTION = Pattern.compile(REGEX_EMOTION);

public static final Pattern PATTERN_URL = Pattern.compile(REGEX_URL);

public static final Pattern PATTERN_AT = Pattern.compile(REGEX_AT);

public static final String SCHEME_TOPIC = "topic:";

public static final String SCHEME_URL = "url:";

public static final String SCHEME_AT = "at:";

}

提取匹配部分并使用 SpannableString 格式化

我將此過程寫到一個方法內了,下面直接上代碼,代碼中有詳細的注釋解釋:

/**

* 格式化微博文本

*

* @param context 上下文

* @param source 源文本

* @param textView 目標 TextView

* @return SpannableStringBuilder

*/

public static SpannableStringBuilder formatWeiBoContent(Context context, String source, TextView textView) {

// 獲取到 TextView 的文字大小,后面的 ImageSpan 需要用到該值

int textSize = (int) textView.getTextSize();

// 若要部分 SpannableString 可點擊,需要如下設置

textView.setMovementMethod(LinkMovementMethod.getInstance());

// 將要格式化的 String 構建成一個 SpannableStringBuilder

SpannableStringBuilder value = new SpannableStringBuilder(source);

// 使用正則匹配話題

Linkify.addLinks(value, WeiboPattern.PATTERN_TOPIC, WeiboPattern.SCHEME_TOPIC);

// 使用正則匹配鏈接

Linkify.addLinks(value, WeiboPattern.PATTERN_URL, WeiboPattern.SCHEME_URL);

// 使用正則匹配@用戶

Linkify.addLinks(value, WeiboPattern.PATTERN_AT, WeiboPattern.SCHEME_AT);

// 自定義的匹配部分的點擊效果

MyClickableSpan clickSpan;

// 獲取上面到所有 addLinks 后的匹配部分(這里一個匹配項被封裝成了一個 URLSpan 對象)

URLSpan[] urlSpans = value.getSpans(0, value.length(), URLSpan.class);

// 遍歷所有的 URLSpan

for (final URLSpan urlSpan : urlSpans) {

// 點擊匹配部分效果

clickSpan = new MyClickableSpan() {

@Override

public void onClick(View view) {

ToastUtils.makeShort(urlSpan.getURL());

}

};

// 話題

if (urlSpan.getURL().startsWith(WeiboPattern.SCHEME_TOPIC)) {

int start = value.getSpanStart(urlSpan);

int end = value.getSpanEnd(urlSpan);

value.removeSpan(urlSpan);

// 格式化話題部分文本

value.setSpan(clickSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

}

// @用戶

if (urlSpan.getURL().startsWith(WeiboPattern.SCHEME_AT)) {

int start = value.getSpanStart(urlSpan);

int end = value.getSpanEnd(urlSpan);

value.removeSpan(urlSpan);

// 格式化@用戶部分文本

value.setSpan(clickSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

}

// 鏈接

if (urlSpan.getURL().startsWith(WeiboPattern.SCHEME_URL)) {

int start = value.getSpanStart(urlSpan);

int end = value.getSpanEnd(urlSpan);

value.removeSpan(urlSpan);

SpannableStringBuilder urlSpannableString = getUrlTextSpannableString(context, urlSpan.getURL(), textSize);

value.replace(start, end, urlSpannableString);

// 格式化鏈接部分文本

value.setSpan(clickSpan, start, start + urlSpannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

}

}

// 表情需要單獨格式化

Matcher emotionMatcher = WeiboPattern.PATTERN_EMOTION.matcher(value);

while (emotionMatcher.find()) {

String emotion = emotionMatcher.group();

int start = emotionMatcher.start();

int end = emotionMatcher.end();

int resId = EmotionUtils.getImageByName(emotion);

if (resId != -1) { // 表情匹配

L.e("find emotion: " + emotion);

Drawable drawable = context.getResources().getDrawable(resId);

drawable.setBounds(0, 0, (int) (textSize * 1.3), (int) (textSize * 1.3));

// 自定義的 VerticalImageSpan ,可解決默認的 ImageSpan 不垂直居中的問題

VerticalImageSpan imageSpan = new VerticalImageSpan(drawable);

value.setSpan(imageSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

}

}

return value;

}

private static SpannableStringBuilder getUrlTextSpannableString(Context context, String source, int size) {

SpannableStringBuilder builder = new SpannableStringBuilder(source);

String prefix = " ";

builder.replace(0, prefix.length(), prefix);

Drawable drawable = context.getResources().getDrawable(R.drawable.ic_status_link);

drawable.setBounds(0, 0, size, size);

builder.setSpan(new VerticalImageSpan(drawable), prefix.length(), source.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

builder.append(" 網頁鏈接");

return builder;

}

getUrlTextSpannableString():方法是用來返回一個圖標+”網頁鏈接” SpannableString,用于替換鏈接文本

上面將”話題”、”表情”、”網頁鏈接”都用了addLinks方法來標記的,然后統一處理。表情則是單獨處理的。

表情則使用如下方法事先做好映射:

public class EmotionUtils {

public static LinkedHashMap sMap;

static {

sMap = new LinkedHashMap<>();

sMap.put("[doge]", R.drawable.d_doge);

sMap.put("[污]", R.drawable.d_wu);

}

public static int getImageByName(String name) {

Integer integer = sMap.get(name);

return integer == null ? -1 : integer;

}

}

還有剛才說到的自定義 MyClickableSpan 修改默認的樣式:

public class MyClickableSpan extends ClickableSpan {

@Override

public void onClick(View view) {

}

@Override

public void updateDrawState(TextPaint ds) {

super.updateDrawState(ds);

ds.setColor(0xff03A9F4);

ds.setUnderlineText(false);

}

}

另外,由于默認的 ImageSpan 在 TextView 有使用android:lineSpacingExtra屬性時,不會垂直居中,所以使用到了網上的一個繼承自 ImageSpan 的 VerticalImageSpan 可以做到保持圖片在 TextView 內保持垂直居中:

public class VerticalImageSpan extends ImageSpan {

public VerticalImageSpan(Drawable drawable) {

super(drawable);

}

/**

* update the text line height

*/

@Override

public int getSize(Paint paint, CharSequence text, int start, int end,

Paint.FontMetricsInt fontMetricsInt) {

Drawable drawable = getDrawable();

Rect rect = drawable.getBounds();

if (fontMetricsInt != null) {

Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();

int fontHeight = fmPaint.descent - fmPaint.ascent;

int drHeight = rect.bottom - rect.top;

int centerY = fmPaint.ascent + fontHeight / 2;

fontMetricsInt.ascent = centerY - drHeight / 2;

fontMetricsInt.top = fontMetricsInt.ascent;

fontMetricsInt.bottom = centerY + drHeight / 2;

fontMetricsInt.descent = fontMetricsInt.bottom;

}

return rect.right;

}

/**

* see detail message in android.text.TextLine

*

* @param canvas the canvas, can be null if not rendering

* @param text the text to be draw

* @param start the text start position

* @param end the text end position

* @param x the edge of the replacement closest to the leading margin

* @param top the top of the line

* @param y the baseline

* @param bottom the bottom of the line

* @param paint the work paint

*/

@Override

public void draw(Canvas canvas, CharSequence text, int start, int end,

float x, int top, int y, int bottom, Paint paint) {

Drawable drawable = getDrawable();

canvas.save();

Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();

int fontHeight = fmPaint.descent - fmPaint.ascent;

int centerY = y + fmPaint.descent - fontHeight / 2;

int transY = centerY - (drawable.getBounds().bottom - drawable.getBounds().top) / 2;

canvas.translate(x, transY);

drawable.draw(canvas);

canvas.restore();

}

}

然后直接調用該方法格式化:

mTextView.setText(formatWeiBoContent(this,mTextView.getText().toString(),mTextView))

最終的效果圖和文章開頭效果一樣了,并且可以點擊,這里展示了點擊”網頁鏈接”時彈出的 Toast 提示:

總結

本文僅介紹了 SpannableString 常用的一些場景,例如修改特定文本的顏色,替換特定文本,特定文本的點擊事件,但是 SpannableString 的強大遠不止如此。SpannableString 的更多用法可閱讀官方文檔。好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

總結

以上是生活随笔為你收集整理的android url格式化,Android利用SpannableString实现格式化微博内容的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 一边摸内裤一边吻胸 | 91爱看| 九九九九九伊人 | 91超碰人人 | 国产草草| 欧洲毛片 | 狠狠躁18三区二区一区传媒剧情 | jzjzjz欧美丰满少妇 | 久久精品天天中文字幕人妻 | 欧美成人精品一区二区综合免费 | 日本无翼乌邪恶大全彩h | 免费视频99| 久久99久久99精品蜜柚传媒 | 黄色成人毛片 | av在线超碰| 久久综合一区二区三区 | 青青青青青青草 | 成人av手机在线 | 密乳av| 国产国语videosex另类 | 夜夜夜影院 | 国产区第一页 | 欧美成人乱码一区二区三区 | 男人的网站在线观看 | 亚洲女女做受ⅹxx高潮 | 97超碰人人澡人人爱学生 | 调教驯服丰满美艳麻麻在线视频 | 欧美综合自拍亚洲综合图片区 | 91视频色| 久久久久久久久久久99 | 黄色国产片| 久久免费视屏 | cao在线| 久久精品男人的天堂 | 7777久久亚洲中文字幕 | 国产高清免费在线观看 | 欧美情趣视频 | 九月婷婷| 网友自拍咪咪爱 | 中文字幕在线三区 | 久久久久亚洲av无码网站 | 国产美女在线精品 | 欧美成人国产 | av看片在线| 激情xxxx | 亚洲欧洲精品在线 | 午夜一区二区三区免费观看 | 亲子乱一区二区三区 | 性生活毛片 | 成人精品国产免费网站 | 久久午夜鲁丝 | 葵司一区二区 | 日韩激情视频在线观看 | 亚洲a在线观看 | 日韩在线视频免费观看 | 欧美天堂网站 | 亚洲卡一| 自拍超碰 | 992tv在线影院 | 日本v视频| 欧美色图俺去了 | 国产99久久久欧美黑人 | 欧美日韩不卡合集视频 | 中文区中文字幕免费看 | 老女人人体欣赏a√s | 久久久久久久女国产乱让韩 | 久久久久久久久福利 | 天天摸天天做天天爽水多 | 日韩精品一区二区三区在线视频 | 色葡萄影院 | 国产av无码专区亚洲av毛网站 | 台湾佬成人中文网222vvv | 欧美一区在线看 | 狠狠操狠狠操 | 中文在线字幕免费观看 | 精品免费国产一区二区三区 | 亚洲国产综合久久 | 国产白袜脚足j棉袜在线观看 | 神马午夜dy888 | 隔壁邻居是巨爆乳寡妇 | 国产精品毛片在线 | 中文字幕色图 | 亚洲在线成人 | 久久精品三级视频 | 女人性做爰100部免费 | 久久精品国产亚洲AV成人婷婷 | 麻豆入口 | 日韩素人| 精品无码人妻一区二区免费蜜桃 | 中文字幕国产日韩 | 五月天亚洲综合 | 日韩精品一区二 | 五月天六月婷婷 | 性色av一区 | 91麻豆精品91久久久久同性 | 亚洲一区二区黄 | 国产av无码专区亚洲精品 | 国产一区资源 | 日本九九热 |