下面列出了android.text.SpannableStringBuilder#setSpan ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static SpannableStringBuilder createSpan(Context context, String text, ImageSpanTag[] tags)
{
SpannableStringBuilder span = new SpannableStringBuilder(text);
ImageSpan blank = createImageSpan(context, R.drawable.ic_transparent, 0, 0, R.color.transparent);
for (ImageSpanTag tag : tags)
{
String spanTag = tag.getTag();
ImageSpan imageSpan = (tag.getSpan() == null) ? blank : tag.getSpan();
int tagPos;
while ((tagPos = text.indexOf(spanTag)) >= 0)
{
int tagEnd = tagPos + spanTag.length();
//Log.d("DEBUG", "tag=" + spanTag + ", tagPos=" + tagPos + ", " + tagEnd + ", text=" + text);
span.setSpan(createImageSpan(imageSpan), tagPos, tagEnd, ImageSpan.ALIGN_BASELINE);
text = text.substring(0, tagPos) + tag.getBlank() + text.substring(tagEnd);
}
}
return span;
}
/**
* 文字格式化,适用但不局限于心得内容,用于处理给定内容 str 中的标签
*
* @param str 给定内容
*
* @return s
*/
public static SpannableStringBuilder covArticleContent(String str) {
if (TextUtils.isEmpty(str)) {
return null;
}
SpannableStringBuilder builder = new SpannableStringBuilder(str);
List<String> tagList = RegexUtil.getMathcherStr(str, RegexUtil.topicValReg);
if (null != tagList && tagList.size() != 0) {
int fromIndex = 0;
for (String tagVal : tagList) {
int _start = str.indexOf(tagVal, fromIndex);
builder.setSpan(new ForegroundColorSpan(Color.parseColor("#ffaa31")),
_start, _start + tagVal.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
builder.setSpan(new AbsoluteSizeSpan(0, true), _start + tagVal.indexOf("["), _start + tagVal.indexOf("]") + 1,
Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
fromIndex = _start + tagVal.length();
}
}
return builder;
}
public static void setHtmlWithLinkClickHandler(TextView tv, String html,
Action1<String> linkClickHandler) {
CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
for (URLSpan span : urls) {
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
ClickableSpan clickable = new ClickableSpan() {
public void onClick(View view) {
linkClickHandler.call(span.getURL());
}
};
strBuilder.setSpan(clickable, start, end, flags);
strBuilder.removeSpan(span);
}
tv.setText(strBuilder);
tv.setMovementMethod(LinkMovementMethod.getInstance());
}
public static void handlerEmojiText(TextView comment, String content, Context context) throws IOException {
SpannableStringBuilder sb = new SpannableStringBuilder(content);
String regex = "\\[(\\S+?)\\]";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(content);
Iterator<Emoji> iterator;
Emoji emoji = null;
while (m.find()) {
iterator = emojiList.iterator();
String tempText = m.group();
while (iterator.hasNext()) {
emoji = iterator.next();
if (tempText.equals(emoji.getContent())) {
//转换为Span并设置Span的大小
sb.setSpan(new ImageSpan(context, decodeSampledBitmapFromResource(context.getResources(), emoji.getImageUri()
, dip2px(context, 18), dip2px(context, 18))),
m.start(), m.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
}
}
}
comment.setText(sb);
}
@Override
public Notification buildNotification(Context context) {
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
new Intent(context, MainActivity.class), 0);
Notification page2 = buildBasicNotification(context)
.extend(new Notification.WearableExtender()
.setHintShowBackgroundOnly(true)
.setBackground(BitmapFactory.decodeResource(context.getResources(),
R.drawable.example_big_picture)))
.build();
Notification page3 = buildBasicNotification(context)
.setContentTitle(context.getString(R.string.third_page))
.setContentText(null)
.extend(new Notification.WearableExtender()
.setContentAction(0 /* action A */))
.build();
SpannableStringBuilder choice2 = new SpannableStringBuilder(
"This choice is best");
choice2.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 5, 11, 0);
return buildBasicNotification(context)
.extend(new Notification.WearableExtender()
.addAction(new Notification.Action(R.mipmap.ic_launcher,
context.getString(R.string.action_a), pendingIntent))
.addAction(new Notification.Action.Builder(R.mipmap.ic_launcher,
context.getString(R.string.reply), pendingIntent)
.addRemoteInput(new RemoteInput.Builder(MainActivity.KEY_REPLY)
.setChoices(new CharSequence[] {
context.getString(R.string.choice_1),
choice2 })
.build())
.build())
.addPage(page2)
.addPage(page3))
.build();
}
private static CharSequence removeJumpingBeansSpans(Spanned text) {
SpannableStringBuilder sbb = new SpannableStringBuilder(text.toString());
Object[] spans = text.getSpans(0, text.length(), Object.class);
for (Object span : spans) {
if (!(span instanceof JumpingBeansSpan)) {
sbb.setSpan(span, text.getSpanStart(span),
text.getSpanEnd(span), text.getSpanFlags(span));
}
}
return sbb;
}
public SpannableStringBuilder getMergedBody() {
SpannableStringBuilder body = new SpannableStringBuilder(MessageUtils.filterLtrRtl(this.body).trim());
Message current = this;
while (current.mergeable(current.next())) {
current = current.next();
if (current == null) {
break;
}
body.append("\n\n");
body.setSpan(new MergeSeparator(), body.length() - 2, body.length(), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
body.append(MessageUtils.filterLtrRtl(current.getBody()).trim());
}
return body;
}
private static void setColorSpan(
SpannableStringBuilder builder, int start, int end, int color) {
if (color == Color.WHITE) {
// White is treated as the default color (i.e. no span is attached).
return;
}
builder.setSpan(new ForegroundColorSpan(color), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
private static void setText(
SpannableStringBuilder builder, Object key, CharSequence text, String bootstrap) {
int start = builder.getSpanStart(key);
int end = builder.getSpanEnd(key);
if (start == -1) {
start = TextUtils.indexOf(builder, bootstrap);
end = start + bootstrap.length();
builder.setSpan(key, start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
builder.replace(start, end, text);
}
private void initTextRightColor(SpannableStringBuilder stringBuilder, int start) {
if (mRightColor != null) {
int color = mRightColor.getColorForState(getDrawableState(), 0);
if (color != mCurRightColor) {
mCurRightColor = color;
}
ForegroundColorSpan foregroundRightColor = new ForegroundColorSpan(mCurRightColor);
stringBuilder.setSpan(foregroundRightColor, start, stringBuilder.length()
, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
mCurRightColor = getCurrentTextColor();
}
}
private static void startFont(SpannableStringBuilder text,
Attributes attributes) {
String color = attributes.getValue("", "color");
String face = attributes.getValue("", "face");
int len = text.length();
text.setSpan(new Font(color, face), len, len, Spannable.SPAN_MARK_MARK);
}
public Spannable buildCounterSpannable(String label, int value) {
SpannableStringBuilder contentString = new SpannableStringBuilder();
contentString.append(String.valueOf(value));
contentString.append("\n");
int start = contentString.length();
contentString.append(label);
contentString.setSpan(new TextAppearanceSpan(context, R.style.TextAppearance_Second_Light), start, contentString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return contentString;
}
private static void applySpansForTag(String cueId, StartTag startTag, SpannableStringBuilder text,
List<WebvttCssStyle> styles, List<StyleMatch> scratchStyleMatches) {
int start = startTag.position;
int end = text.length();
switch(startTag.name) {
case TAG_BOLD:
text.setSpan(new StyleSpan(STYLE_BOLD), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TAG_ITALIC:
text.setSpan(new StyleSpan(STYLE_ITALIC), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TAG_UNDERLINE:
text.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TAG_CLASS:
case TAG_LANG:
case TAG_VOICE:
case "": // Case of the "whole cue" virtual tag.
break;
default:
return;
}
scratchStyleMatches.clear();
getApplicableStyles(styles, cueId, startTag, scratchStyleMatches);
int styleMatchesCount = scratchStyleMatches.size();
for (int i = 0; i < styleMatchesCount; i++) {
applyStyleToText(text, scratchStyleMatches.get(i).style, start, end);
}
}
private void updateTextSearchSpan() {
if (stickerSetName != null && stickerSetNameSearchLength != 0) {
SpannableStringBuilder builder = new SpannableStringBuilder(stickerSetName);
try {
builder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_chat_emojiPanelStickerSetNameHighlight)), stickerSetNameSearchIndex, stickerSetNameSearchIndex + stickerSetNameSearchLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception ignore) {
}
textView.setText(Emoji.replaceEmoji(builder, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false));
}
}
private static void insertClickSpanLink(SpannableStringBuilder strBuilder, String message, final boolean isUser, final long id) {
if (message.length() == 0) {
return;
}
strBuilder.append(message);
if (id != 0) {
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View widget) {
if (isUser) {
if (id > 0) {
gotToUserRoom(id);
}
} else {
if (id > 0) {
goToRoom(id);
}
}
}
@Override
public void updateDrawState(TextPaint ds) {
if (G.isDarkTheme) {
ds.linkColor = Color.parseColor(G.textTitleTheme);
} else {
ds.linkColor = Color.DKGRAY;
}
super.updateDrawState(ds);
}
};
strBuilder.setSpan(clickableSpan, strBuilder.length() - message.length(), strBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
/**
* 处理html数据的高亮与响应
*
* @param tv
* @param content
* @return
*/
public static TextView handleHtmlText(TextView tv, String content) {
SpannableStringBuilder sp = new SpannableStringBuilder(Html.fromHtml(content));
URLSpan[] urlSpans = sp.getSpans(0, sp.length(), URLSpan.class);
for (final URLSpan span : urlSpans) {
int start = sp.getSpanStart(span);
int end = sp.getSpanEnd(span);
sp.setSpan(getClickableSpan(span.getURL()), start, end, Spanned
.SPAN_EXCLUSIVE_EXCLUSIVE);
}
tv.setText(sp);
tv.setMovementMethod(LinkMovementMethod.getInstance());
return tv;
}
@Override
public void start(Block block, SpannableStringBuilder text) {
final int len = text.length();
text.setSpan(this, len, len, Spannable.SPAN_MARK_MARK);
}
private void drawNumericClock(Canvas canvas) {
if (showBorder) {
drawCustomBorder(canvas);
}
if (clockBackground != null) {
Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap bitmap = ((BitmapDrawable) clockBackground).getBitmap();
RectF rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas tCanvas = new Canvas(output);
switch (borderStyle) {
case rectangle:
tCanvas.drawRect(defaultRectF, paint);
break;
case circle:
tCanvas.drawCircle(centerX, centerY, radius, paint);
break;
case rounded_rectangle:
float rx = radius - (radius * (100 - borderRadiusRx)) / 100;
float ry = radius - (radius * (100 - borderRadiusRy)) / 100;
tCanvas.drawRoundRect(defaultRectF, rx, ry, paint);
break;
}
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
tCanvas.drawBitmap(bitmap, null, rectF, paint);
canvas.drawBitmap(output, null, rectF, new Paint());
}
TextPaint textPaint = new TextPaint();
textPaint.setAntiAlias(true);
textPaint.setTypeface(valuesFont);
textPaint.setTextSize(size * 0.22f);
textPaint.setColor(this.valuesColor);
SpannableStringBuilder spannableString = new SpannableStringBuilder();
int amPm = mCalendar.get(Calendar.AM_PM);
String minute = String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.MINUTE));
String second = String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.SECOND));
if (this.numericShowSeconds) {
if (this.numericFormat == NumericFormat.hour_12) {
spannableString.append(String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.HOUR)));
spannableString.append(":");
spannableString.append(minute);
spannableString.append(".");
spannableString.append(second);
spannableString.append(amPm == Calendar.AM ? "AM" : "PM");
spannableString.setSpan(new RelativeSizeSpan(0.3f), spannableString.toString().length() - 2, spannableString.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // se superscript percent
} else {
spannableString.append(String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.HOUR_OF_DAY)));
spannableString.append(":");
spannableString.append(minute);
spannableString.append(".");
spannableString.append(second);
}
} else {
if (this.numericFormat == NumericFormat.hour_12) {
spannableString.append(String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.HOUR)));
spannableString.append(":");
spannableString.append(minute);
spannableString.append(amPm == Calendar.AM ? "AM" : "PM");
spannableString.setSpan(new RelativeSizeSpan(0.4f), spannableString.toString().length() - 2, spannableString.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // se superscript percent
} else {
spannableString.append(String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.HOUR_OF_DAY)));
spannableString.append(":");
spannableString.append(minute);
}
}
StaticLayout layout = new StaticLayout(spannableString, textPaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER, 1, 1, true);
canvas.translate(centerX - layout.getWidth() / 2, centerY - layout.getHeight() / 2);
layout.draw(canvas);
}
private static void recursivePrepareSpannableIndexes(
Context context,
String fullText,
SpannableStringBuilder text,
List<IconFontDescriptorWrapper> iconFontDescriptors,
int start) {
// Try to find a {...} in the string and extract expression from it
String stringText = text.toString();
int startIndex = stringText.indexOf("{", start);
if (startIndex == -1) return;
int endIndex = stringText.indexOf("}", startIndex) + 1;
if (endIndex == -1) return;
String expression = stringText.substring(startIndex + 1, endIndex - 1);
// Split the expression and retrieve the icon key
String[] strokes = expression.split(" ");
String key = strokes[0];
// Loop through the descriptors to find a key match
IconFontDescriptorWrapper iconFontDescriptor = null;
Icon icon = null;
for (int i = 0; i < iconFontDescriptors.size(); i++) {
iconFontDescriptor = iconFontDescriptors.get(i);
icon = iconFontDescriptor.getIcon(key);
if (icon != null) break;
}
// If no match, ignore and continue
if (icon == null) {
recursivePrepareSpannableIndexes(context, fullText, text, iconFontDescriptors, endIndex);
return;
}
// See if any more stroke within {} should be applied
float iconSizePx = -1;
int iconColor = Integer.MAX_VALUE;
float iconSizeRatio = -1;
boolean spin = false;
boolean baselineAligned = false;
for (int i = 1; i < strokes.length; i++) {
String stroke = strokes[i];
// Look for "spin"
if (stroke.equalsIgnoreCase("spin")) {
spin = true;
}
// Look for "baseline"
else if (stroke.equalsIgnoreCase("baseline")) {
baselineAligned = true;
}
// Look for an icon size
else if (stroke.matches("([0-9]*(\\.[0-9]*)?)dp")) {
iconSizePx = dpToPx(context, Float.valueOf(stroke.substring(0, stroke.length() - 2)));
} else if (stroke.matches("([0-9]*(\\.[0-9]*)?)sp")) {
iconSizePx = spToPx(context, Float.valueOf(stroke.substring(0, stroke.length() - 2)));
} else if (stroke.matches("([0-9]*)px")) {
iconSizePx = Integer.valueOf(stroke.substring(0, stroke.length() - 2));
} else if (stroke.matches("@dimen/(.*)")) {
iconSizePx = getPxFromDimen(context, context.getPackageName(), stroke.substring(7));
if (iconSizePx < 0)
throw new IllegalArgumentException("Unknown resource " + stroke + " in \"" + fullText + "\"");
} else if (stroke.matches("@android:dimen/(.*)")) {
iconSizePx = getPxFromDimen(context, ANDROID_PACKAGE_NAME, stroke.substring(15));
if (iconSizePx < 0)
throw new IllegalArgumentException("Unknown resource " + stroke + " in \"" + fullText + "\"");
} else if (stroke.matches("([0-9]*(\\.[0-9]*)?)%")) {
iconSizeRatio = Float.valueOf(stroke.substring(0, stroke.length() - 1)) / 100f;
}
// Look for an icon color
else if (stroke.matches("#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})")) {
iconColor = Color.parseColor(stroke);
} else if (stroke.matches("@color/(.*)")) {
iconColor = getColorFromResource(context, context.getPackageName(), stroke.substring(7));
if (iconColor == Integer.MAX_VALUE)
throw new IllegalArgumentException("Unknown resource " + stroke + " in \"" + fullText + "\"");
} else if (stroke.matches("@android:color/(.*)")) {
iconColor = getColorFromResource(context, ANDROID_PACKAGE_NAME, stroke.substring(15));
if (iconColor == Integer.MAX_VALUE)
throw new IllegalArgumentException("Unknown resource " + stroke + " in \"" + fullText + "\"");
} else {
throw new IllegalArgumentException("Unknown expression " + stroke + " in \"" + fullText + "\"");
}
}
// Replace the character and apply the typeface
text = text.replace(startIndex, endIndex, "" + icon.character());
text.setSpan(new CustomTypefaceSpan(icon,
iconFontDescriptor.getTypeface(context),
iconSizePx, iconSizeRatio, iconColor, spin, baselineAligned),
startIndex, startIndex + 1,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
recursivePrepareSpannableIndexes(context, fullText, text, iconFontDescriptors, startIndex);
}
private static void setSpan(SpannableStringBuilder builder, Object what) {
builder.setSpan(what, 0, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}