Java Code Examples for android.text.SpannableStringBuilder#replace()
The following examples show how to use
android.text.SpannableStringBuilder#replace() .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: ChatActivityEnterView.java From TelePlus-Android with GNU General Public License v2.0 | 6 votes |
public void replaceWithText(int start, int len, CharSequence text, boolean parseEmoji) { try { SpannableStringBuilder builder = new SpannableStringBuilder(messageEditText.getText()); builder.replace(start, start + len, text); if (parseEmoji) { Emoji.replaceEmoji(builder, messageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); } messageEditText.setText(builder); messageEditText.setSelection(start + text.length()); } catch (Exception e) { FileLog.e(e); } }
Example 2
Source File: ChatActivityEnterView.java From TelePlus-Android with GNU General Public License v2.0 | 6 votes |
public void replaceWithText(int start, int len, CharSequence text, boolean parseEmoji) { try { SpannableStringBuilder builder = new SpannableStringBuilder(messageEditText.getText()); builder.replace(start, start + len, text); if (parseEmoji) { Emoji.replaceEmoji(builder, messageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); } messageEditText.setText(builder); messageEditText.setSelection(start + text.length()); } catch (Exception e) { FileLog.e(e); } }
Example 3
Source File: PhotoViewerCaptionEnterView.java From Telegram-FOSS with GNU General Public License v2.0 | 6 votes |
public void replaceWithText(int start, int len, CharSequence text, boolean parseEmoji) { try { SpannableStringBuilder builder = new SpannableStringBuilder(messageEditText.getText()); builder.replace(start, start + len, text); if (parseEmoji) { Emoji.replaceEmoji(builder, messageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); } messageEditText.setText(builder); if (start + text.length() <= messageEditText.length()) { messageEditText.setSelection(start + text.length()); } else { messageEditText.setSelection(messageEditText.length()); } } catch (Exception e) { FileLog.e(e); } }
Example 4
Source File: Phrase.java From phrase with Apache License 2.0 | 5 votes |
@Override void expand(SpannableStringBuilder target, Map<String, CharSequence> data) { value = data.get(key); int replaceFrom = getFormattedStart(); // Add 2 to account for the opening and closing brackets. int replaceTo = replaceFrom + key.length() + 2; target.replace(replaceFrom, replaceTo, value); }
Example 5
Source File: PaymentFormActivity.java From TelePlus-Android with GNU General Public License v2.0 | 5 votes |
private void updateSavePaymentField() { if (bottomCell[0] == null || sectionCell[2] == null) { return; } if ((paymentForm.password_missing || paymentForm.can_save_credentials) && (webView == null || webView != null && !webviewLoading)) { SpannableStringBuilder text = new SpannableStringBuilder(LocaleController.getString("PaymentCardSavePaymentInformationInfoLine1", R.string.PaymentCardSavePaymentInformationInfoLine1)); if (paymentForm.password_missing) { loadPasswordInfo(); text.append("\n"); int len = text.length(); String str2 = LocaleController.getString("PaymentCardSavePaymentInformationInfoLine2", R.string.PaymentCardSavePaymentInformationInfoLine2); int index1 = str2.indexOf('*'); int index2 = str2.lastIndexOf('*'); text.append(str2); if (index1 != -1 && index2 != -1) { index1 += len; index2 += len; bottomCell[0].getTextView().setMovementMethod(new AndroidUtilities.LinkMovementMethodMy()); text.replace(index2, index2 + 1, ""); text.replace(index1, index1 + 1, ""); text.setSpan(new LinkSpan(), index1, index2 - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } checkCell1.setEnabled(true); bottomCell[0].setText(text); checkCell1.setVisibility(View.VISIBLE); bottomCell[0].setVisibility(View.VISIBLE); sectionCell[2].setBackgroundDrawable(Theme.getThemedDrawable(sectionCell[2].getContext(), R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } else { checkCell1.setVisibility(View.GONE); bottomCell[0].setVisibility(View.GONE); sectionCell[2].setBackgroundDrawable(Theme.getThemedDrawable(sectionCell[2].getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } }
Example 6
Source File: IconicFontEngine.java From android-IconicFontEngine with Apache License 2.0 | 5 votes |
private static CharSequence render(SpannableStringBuilder spannableStringBuilder, ArrayList<IconicFontEngine> engines) { int caret = 0; List<Pair<Integer, IconicFontEngine>> positions = new ArrayList<>(); while (true) { StringBuilder text = new StringBuilder(spannableStringBuilder.toString()); int startBracketIndex = text.indexOf("{", caret); int endBracketIndex = text.indexOf("}", startBracketIndex + 1); if (startBracketIndex == -1 || endBracketIndex == -1) { break; } String iconString = text.substring(startBracketIndex + 1, endBracketIndex); boolean found = false; for (IconicFontEngine engine : engines) { Character fontChar = engine.getIconicFontMap().get(iconString); if (fontChar != null) { spannableStringBuilder.replace(startBracketIndex, endBracketIndex + 1, String.valueOf(fontChar)); positions.add(new Pair<>(startBracketIndex, engine)); caret = startBracketIndex + 1; found = true; break; } } if (!found) { Log.w(TAG, "{" + iconString + "} not fount in fontMaps"); caret = endBracketIndex + 1; } } for (Pair<Integer, IconicFontEngine> pair : positions) { setSpan(pair.second.getTypeface(), spannableStringBuilder, pair.first); } return spannableStringBuilder; }
Example 7
Source File: RichEditText.java From GSYRickText with MIT License | 5 votes |
/** * 处理话题和表情 * * @param context 上下文 * @param text 输入文本 * @param color 颜色 * @param listTopic 话题列表 * @return Spannable */ private static Spannable resolveTopicInsert(Context context, String text, String color, List<TopicModel> listTopic) { Spannable spannable; if (listTopic != null && listTopic.size() > 0) { Map<String, String> topics = new HashMap<>(); for (TopicModel topicModel : listTopic) { topics.put(topicModel.getTopicName(), topicModel.getTopicName()); } //查找## int length = text.length(); Pattern pattern = Pattern.compile("#[^\\s]+?#"); Matcher matcher = pattern.matcher(text); SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text); for (int i = 0; i < length; i++) { if (matcher.find()) { String name = text.substring(matcher.start(), matcher.end()); if (topics.containsKey(name)) { //直接用span会导致后面没文字的时候新输入的一起变色 Spanned htmlText = Html.fromHtml(String.format("<font color='%s'>" + name + "</font>", color)); spannableStringBuilder.replace(matcher.start(), matcher.start() + name.length(), htmlText); } } } spannable = spannableStringBuilder; SmileUtils.addSmiles(context, spannable); } else { spannable = TextCommonUtils.getEmojiText(context, text); } SmileUtils.addSmiles(context, spannable); return spannable; }
Example 8
Source File: BBCodeReader.java From AndFChat with GNU General Public License v3.0 | 5 votes |
public void doReplacement(SpannableStringBuilder text) { if (key != null) { String textAsString = text.toString(); int start = textAsString.indexOf(key); text.replace(start, start + key.length(), replacement); } }
Example 9
Source File: TermsOfServiceView.java From Telegram with GNU General Public License v2.0 | 5 votes |
private static void addBulletsToText(SpannableStringBuilder builder, char bulletChar, int gapWidth, int color, int radius) { for (int i = 0, until = builder.length() - 2; i < until; i++) { if (builder.charAt(i) == '\n' && builder.charAt(i + 1) == bulletChar && builder.charAt(i + 2) == ' ') { final BulletSpan span = new BulletSpan(gapWidth, color, radius); builder.replace(i + 1, i + 3, "\0\0"); builder.setSpan(span, i + 1, i + 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } }
Example 10
Source File: AutoRunCommandListEditText.java From revolution-irc with GNU General Public License v3.0 | 5 votes |
private static String getTextWithPasswords(CharSequence seq) { SpannableStringBuilder lstr = new SpannableStringBuilder(seq); for (PasswordSpan span : lstr.getSpans(0, lstr.length(), PasswordSpan.class)) { lstr.replace(lstr.getSpanStart(span), lstr.getSpanEnd(span), span.mPassword); lstr.removeSpan(span); } return lstr.toString(); }
Example 11
Source File: Editor.java From editor with GNU General Public License v3.0 | 5 votes |
@SuppressWarnings("deprecation") private void aboutClicked() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.appName); DateFormat dateFormat = DateFormat.getDateTimeInstance(); SpannableStringBuilder spannable = new SpannableStringBuilder(getText(R.string.version)); Pattern pattern = Pattern.compile("%s"); Matcher matcher = pattern.matcher(spannable); if (matcher.find()) spannable.replace(matcher.start(), matcher.end(), BuildConfig.VERSION_NAME); matcher.reset(spannable); if (matcher.find()) spannable.replace(matcher.start(), matcher.end(), dateFormat.format(BuildConfig.BUILT)); builder.setMessage(spannable); // Add the button builder.setPositiveButton(R.string.ok, null); // Create the AlertDialog Dialog dialog = builder.show(); // Set movement method TextView text = dialog.findViewById(android.R.id.message); if (text != null) { text.setTextAppearance(builder.getContext(), android.R.style.TextAppearance_Small); text.setMovementMethod(LinkMovementMethod.getInstance()); } }
Example 12
Source File: PatternUtils.java From xifan with Apache License 2.0 | 5 votes |
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.mipmap.ic_status_link); drawable.setBounds(0, 0, size, size); builder.setSpan(new VerticalImageSpan(drawable), prefix.length(), source.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); builder.append(App.getInstance().getString(R.string.text_url_link)); return builder; }
Example 13
Source File: PaymentFormActivity.java From TelePlus-Android with GNU General Public License v2.0 | 5 votes |
private void updateSavePaymentField() { if (bottomCell[0] == null || sectionCell[2] == null) { return; } if ((paymentForm.password_missing || paymentForm.can_save_credentials) && (webView == null || webView != null && !webviewLoading)) { SpannableStringBuilder text = new SpannableStringBuilder(LocaleController.getString("PaymentCardSavePaymentInformationInfoLine1", R.string.PaymentCardSavePaymentInformationInfoLine1)); if (paymentForm.password_missing) { loadPasswordInfo(); text.append("\n"); int len = text.length(); String str2 = LocaleController.getString("PaymentCardSavePaymentInformationInfoLine2", R.string.PaymentCardSavePaymentInformationInfoLine2); int index1 = str2.indexOf('*'); int index2 = str2.lastIndexOf('*'); text.append(str2); if (index1 != -1 && index2 != -1) { index1 += len; index2 += len; bottomCell[0].getTextView().setMovementMethod(new AndroidUtilities.LinkMovementMethodMy()); text.replace(index2, index2 + 1, ""); text.replace(index1, index1 + 1, ""); text.setSpan(new LinkSpan(), index1, index2 - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } checkCell1.setEnabled(true); bottomCell[0].setText(text); checkCell1.setVisibility(View.VISIBLE); bottomCell[0].setVisibility(View.VISIBLE); sectionCell[2].setBackgroundDrawable(Theme.getThemedDrawable(sectionCell[2].getContext(), R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } else { checkCell1.setVisibility(View.GONE); bottomCell[0].setVisibility(View.GONE); sectionCell[2].setBackgroundDrawable(Theme.getThemedDrawable(sectionCell[2].getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } }
Example 14
Source File: CodeTextView.java From android-quiz-php with BSD 2-Clause "Simplified" License | 5 votes |
@Override public void run() { SpannableStringBuilder string = new SpannableStringBuilder(mText); for (Matcher m = code.matcher( mText ); m.find();) { string.replace( m.start(), m.end(), highlight(new SpannableStringBuilder(m.group().replaceAll("\\[\\/?code\\]", ""))) ); } setText(string); }
Example 15
Source File: IssueTimelineAdapter.java From OpenHub with GNU General Public License v3.0 | 4 votes |
void setDesc(IssueEvent model){ SpannableStringBuilder text = new SpannableStringBuilder(model.getActor().getLogin()); text.append(" "); String info; switch (model.getType()){ case reopened: text.append(getString(R.string.issue_reopened)); break; case closed: text.append(getString(R.string.issue_close)); break; case renamed: text.append(getString(R.string.issue_modified)); break; case locked: text.append(getString(R.string.issue_locked_conversation)); break; case unlocked: text.append(getString(R.string.issue_unlocked_conversation)); break; case crossReferenced: if(model.getSource().getType() != null){ info = String.format(getString(R.string.issue_referenced), "#" + model.getSource().getIssue().getTitle()); text.append(info); } break; case assigned: info = String.format(getString(R.string.issue_assigned), model.getAssignee().getLogin()); text.append(info); break; case unassigned: text.append(getString(R.string.issue_unassigned)); break; case milestoned: info = String.format(getString(R.string.issue_added_to_milestone), model.getMilestone().getTitle()); text.append(info); break; case demilestoned: info = String.format(getString(R.string.issue_removed_from_milestone), model.getMilestone().getTitle()); text.append(info); break; case commentDeleted: text.append(getString(R.string.issue_delete_comment)); break; case labeled: info = String.format(getString(R.string.issue_add_label), "[label]"); text.append(info); break; case unlabeled: info = String.format(getString(R.string.issue_remove_label), "[label]"); text.append(info); break; default: // eventIcon.setBackgroundColor(context.getResources().getColor(R.color.transparent)); break; } int labelPos = text.toString().indexOf("[label]"); Label label = model.getLabel(); if(label != null && labelPos >= 0){ text.replace(labelPos, labelPos + 7, label.getName()); text.setSpan(new IssueLabelSpan(context, label), labelPos, labelPos + label.getName().length(), 0); } String timeStr = StringUtils.getNewsTimeStr(context, model.getCreatedAt()); text.append(" ").append(timeStr); desc.setText(text); }
Example 16
Source File: SpanUtils.java From TokenAutoComplete with Apache License 2.0 | 4 votes |
@Nullable public static Spanned ellipsizeWithSpans(@Nullable CharSequence prefix, @Nullable CountSpan countSpan, int tokenCount, @NonNull TextPaint paint, @NonNull CharSequence originalText, float maxWidth) { float countWidth = 0; if (countSpan != null) { //Assume the largest possible number of items for measurement countSpan.setCount(tokenCount); countWidth = countSpan.getCountTextWidthForPaint(paint); } EllipsizeCallback ellipsizeCallback = new EllipsizeCallback(); CharSequence tempEllipsized = TextUtils.ellipsize(originalText, paint, maxWidth - countWidth, TextUtils.TruncateAt.END, false, ellipsizeCallback); SpannableStringBuilder ellipsized = new SpannableStringBuilder(tempEllipsized); if (tempEllipsized instanceof Spanned) { TextUtils.copySpansFrom((Spanned)tempEllipsized, 0, tempEllipsized.length(), Object.class, ellipsized, 0); } if (prefix != null && prefix.length() > ellipsizeCallback.start) { //We ellipsized part of the prefix, so put it back ellipsized.replace(0, ellipsizeCallback.start, prefix); ellipsizeCallback.end = ellipsizeCallback.end + prefix.length() - ellipsizeCallback.start; ellipsizeCallback.start = prefix.length(); } if (ellipsizeCallback.start != ellipsizeCallback.end) { if (countSpan != null) { int visibleCount = ellipsized.getSpans(0, ellipsized.length(), TokenCompleteTextView.TokenImageSpan.class).length; countSpan.setCount(tokenCount - visibleCount); ellipsized.replace(ellipsizeCallback.start, ellipsized.length(), countSpan.getCountText()); ellipsized.setSpan(countSpan, ellipsizeCallback.start, ellipsized.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } return ellipsized; } //No ellipses necessary return null; }
Example 17
Source File: AboutPreference.java From currency with GNU General Public License v3.0 | 4 votes |
@Override protected void onBindDialogView(View view) { super.onBindDialogView(view); // Get version text view TextView version = view.findViewById(R.id.about); // Set version in text view if (version != null) { SpannableStringBuilder builder = new SpannableStringBuilder(version.getText()); Pattern pattern = Pattern.compile("%s"); Matcher matcher = pattern.matcher(builder); if (matcher.find()) builder.replace(matcher.start(), matcher.end(), BuildConfig.VERSION_NAME); version.setText(builder); version.setMovementMethod(LinkMovementMethod.getInstance()); } // Get built text view TextView built = view.findViewById(R.id.built); // Set built date in text view if (built != null) { String d = built.getText().toString(); DateFormat dateFormat = DateFormat.getDateTimeInstance(); String s = String.format(d, dateFormat.format(BuildConfig.BUILT)); built.setText(s); } // Get copyright text view TextView copyright = view.findViewById(R.id.copyright); // Set movement method if (copyright != null) copyright.setMovementMethod(LinkMovementMethod.getInstance()); // Get licence text view TextView licence = view.findViewById(R.id.licence); // Set movement method if (licence != null) licence.setMovementMethod(LinkMovementMethod.getInstance()); }
Example 18
Source File: ParsingUtil.java From grblcontroller with GNU General Public License v3.0 | 4 votes |
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); }
Example 19
Source File: RichEditText.java From GSYRickText with MIT License | 4 votes |
/** * 处理at某人 * * @param text 输入文本 * @param spannable 处理过的文本 * @param color 颜色 * @param listUser 用户列表 * @return Spannable */ private Spannable resolveAtInsert(String text, Spannable spannable, String color, List<UserModel> listUser) { if (listUser == null || listUser.size() <= 0) { return spannable; } //此处保存名字的键值 Map<String, String> names = new HashMap<>(); if (listUser.size() > 0) { for (UserModel userModel : listUser) { names.put(userModel.getUser_name(), userModel.getUser_name()); } } int length = spannable.length(); Pattern pattern = Pattern.compile("@[^\\s]+\\s?"); Matcher matcher = pattern.matcher(spannable); SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(spannable); for (int i = 0; i < length; i++) { if (matcher.find()) { String name = text.substring(matcher.start(), matcher.end()); if (names.containsKey(name.replace("\b", "").replace(" ", ""))) { //直接用span会导致后面没文字的时候新输入的一起变色 Spanned htmlText = Html.fromHtml(String.format("<font color='%s'>" + name + "</font>", color)); spannableStringBuilder.replace(matcher.start(), matcher.start() + name.length(), htmlText); int index = matcher.start() + htmlText.length(); if (index < text.length()) { if (" ".equals(text.subSequence(index - 1, index))) { spannableStringBuilder.replace(index - 1, index, "\b"); } } else { if (text.substring(index - 1).equals(" ")) { spannableStringBuilder.replace(index - 1, index, "\b"); } else { //如果是最后面的没有空格,补上\b spannableStringBuilder.insert(index, "\b"); } } } } } return spannableStringBuilder; }
Example 20
Source File: TweetTextLinkifier.java From twitter-kit-android with Apache License 2.0 | 4 votes |
/** * Swaps display urls in for t.co urls and adjusts the remaining entity indices. * * @param spannable The final formatted text that we are building * @param entities The combined list of media and url entities * @param strippedEntity The trailing entity that we should strip from the text * @param linkListener The link click listener to attach to the span * @param linkColor The link color * @param linkHighlightColor The link background color when pressed */ private static void addUrlEntities(final SpannableStringBuilder spannable, final List<FormattedUrlEntity> entities, final FormattedUrlEntity strippedEntity, final LinkClickListener linkListener, final int linkColor, final int linkHighlightColor) { if (entities == null || entities.isEmpty()) return; int offset = 0; int len; int start; int end; for (final FormattedUrlEntity url : entities) { start = url.start - offset; end = url.end - offset; if (start >= 0 && end <= spannable.length()) { // replace the last photo url with empty string, we can use the start indices as // as simple check, since none of this will work anyways if we have overlapping // entities if (strippedEntity != null && strippedEntity.start == url.start) { spannable.replace(start, end, ""); len = end - start; offset += len; } else if (!TextUtils.isEmpty(url.displayUrl)) { spannable.replace(start, end, url.displayUrl); len = end - (start + url.displayUrl.length()); end -= len; offset += len; final CharacterStyle span = new ClickableLinkSpan(linkHighlightColor, linkColor, false) { @Override public void onClick(View widget) { if (linkListener == null) return; linkListener.onUrlClicked(url.url); } }; spannable.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } } }