下面列出了android.text.SpannableStringBuilder#replace ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
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);
}
}
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);
}
}
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);
}
}
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));
}
}
@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);
}
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));
}
}
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;
}
@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());
}
}
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();
}
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);
}
}
}
public void doReplacement(SpannableStringBuilder text) {
if (key != null) {
String textAsString = text.toString();
int start = textAsString.indexOf(key);
text.replace(start, start + key.length(), replacement);
}
}
/**
* 处理话题和表情
*
* @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;
}
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;
}
@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);
}
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);
}
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);
}
@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;
}
@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());
}
/**
* 处理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;
}
/**
* 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);
}
}
}
}