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:";
}
/**
* 格式化微博文本
*
* @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;
}
public class EmotionUtils {
public static LinkedHashMap<String, Integer> 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;
}
}
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);
}
}
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))
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有