下面列出了怎么用android.text.ParcelableSpan的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* 删除字符的时候,要删除当前位置start和end相等的span
*/
private void handleDelete() {
Editable editable = mEditText.getEditableText();
int cursorPos = mEditText.getSelectionStart();
ParcelableSpan[] parcelableSpans = editable.getSpans(cursorPos, cursorPos, ParcelableSpan.class);
for (ParcelableSpan span : parcelableSpans) {
if (editable.getSpanStart(span) == editable.getSpanEnd(span)) {
editable.removeSpan(span);
}
}
if (isDeleteEnterStr) {
// 删除了回车符,如果回车前后两行只要有一行是block样式,就要合并
mEditText.getRichUtils().mergeBlockSpanAfterDeleteEnter();
}
}
/**
* 光标发生变化的时候,若光标的位置处于某个span的右侧,则将该span的end恢复成包含(inclusive)
*
* @param cursorPos 当前位置
* @param spanClazz 具体的spanClazz
*/
private void restoreSpanEndToInclusive(int cursorPos, Class spanClazz) {
Editable editable = mRichEditText.getEditableText();
ParcelableSpan[] parcelableSpans = (ParcelableSpan[]) editable.getSpans(cursorPos, cursorPos, spanClazz);
for (ParcelableSpan span : parcelableSpans) {
int spanStart = editable.getSpanStart(span);
int spanEnd = editable.getSpanEnd(span);
if (spanEnd == cursorPos) {
editable.removeSpan(span);
if (span instanceof IInlineSpan) {
editable.setSpan(getInlineStyleSpan(spanClazz), spanStart, spanEnd, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
} else if (span instanceof IBlockSpan) {
IBlockSpan blockSpan = (IBlockSpan) span;
IBlockSpan newBlockSpan = getBlockSpan(spanClazz);
editable.setSpan(newBlockSpan, spanStart, spanEnd, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
}
}
}
/**
* Returns a {@link Spannable} which attaches the specified {@link ParcelableSpan} to the given
* substring
*
* @param text Text
* @param span array of {@link ParcelableSpan} that will be applied
* @param spanTexts array of substrings that will be modified
*
* @return {@link Spannable}
*/
@NonNull public Spannable createSpan(String text, ParcelableSpan[] span, String... spanTexts) {
Spannable result = new SpannableString(text);
if (span != null && spanTexts != null && span.length <= spanTexts.length) {
for (int i = 0; i < span.length; i++) {
String spanText = spanTexts[i];
int spanTextStart = text.indexOf(spanText);
if (spanTextStart >= 0
&& spanTextStart < text.length()
&& spanText.length() <= text.length()) {
result.setSpan(span[i], spanTextStart, (spanTextStart + spanText.length()),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
return result;
}
@NonNull
public Spannable createMultiSpan(String text, ParcelableSpan[] span, String... spanTexts) {
Spannable result = new SpannableString(text);
for (ParcelableSpan parcelableSpan : span) {
for (String spanText : spanTexts) {
int spanTextStart = text.indexOf(spanText);
if (spanTextStart >= 0
&& spanTextStart < text.length()
&& spanText.length() <= text.length()) {
result.setSpan(parcelableSpan, spanTextStart, (spanTextStart + spanText.length()),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
return result;
}
@Override public void bindView(CreateStoreDisplayable displayable, int position) {
SpannableFactory spannableFactory = new SpannableFactory();
String followersText = String.format(getContext().getString(R.string.storetab_short_followers),
String.valueOf(displayable.getFollowers()));
ParcelableSpan[] textStyle = {
new StyleSpan(android.graphics.Typeface.BOLD),
new ForegroundColorSpan(displayable.getTextAccentColor())
};
followers.setText(spannableFactory.createMultiSpan(followersText, textStyle,
String.valueOf(displayable.getFollowers())));
String followingText = String.format(getContext().getString(R.string.storetab_short_followings),
String.valueOf(displayable.getFollowings()));
following.setText(spannableFactory.createMultiSpan(followingText, textStyle,
String.valueOf(displayable.getFollowings())));
compositeSubscription.add(RxView.clicks(button)
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(click -> getFragmentNavigator().navigateTo(
ManageStoreFragment.newInstance(new ManageStoreViewModel(), false), true))
.doOnNext(__ -> displayable.getStoreAnalytics()
.sendStoreTabInteractEvent("Login", false))
.subscribe(__ -> {
}, err -> crashReport.log(err)));
}
private void showStats(StoreDisplayable displayable) {
SpannableFactory spannableFactory = new SpannableFactory();
ParcelableSpan[] textStyle = {
new StyleSpan(android.graphics.Typeface.BOLD),
new ForegroundColorSpan(displayable.getTextColor())
};
String firstStatsText = String.format(getContext().getString(displayable.getFirstStatsLabel()),
String.valueOf(displayable.getFirstStatsNumber()));
firstStat.setText(spannableFactory.createMultiSpan(firstStatsText, textStyle,
String.valueOf(displayable.getFirstStatsNumber())));
String secondStatsText =
String.format(getContext().getString(displayable.getSecondStatsLabel()),
String.valueOf(displayable.getSecondStatsNumber()));
secondStat.setText(spannableFactory.createMultiSpan(secondStatsText, textStyle,
String.valueOf(displayable.getSecondStatsNumber())));
}
public static Spannable highlightMatchedChars(String text, String query, SearchEditText.MatchMode matchMode, ParcelableSpan span) {
SpannableString string = new SpannableString(text);
if (matchMode == SearchEditText.MatchMode.START || matchMode == SearchEditText.MatchMode.ADJACENT) {
int index = text.indexOf(query);
if (index != -1)
string.setSpan(span, index, index + query.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
} else if (matchMode == SearchEditText.MatchMode.NONADJACENT) {
int i = 0, j = 0;
for (; i < text.length() && j < query.length(); i++) {
if (text.charAt(i) == query.charAt(j)) {
string.setSpan(span, i, i + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
j++;
}
}
}
return string;
}
static CharSequence subSequence(CharSequence charSequence, int start, int end) {
if (start == 0 && charSequence.length() + 1 == end) {
return charSequence;
}
if (charSequence instanceof Spannable) {
Spannable spannable = (Spannable) charSequence;
Spannable sub = (Spannable) spannable.subSequence(start, end);
for (Class<? extends ParcelableSpan> clazz : SPAN_CLASSES) {
ParcelableSpan[] spannables = spannable.getSpans(start, end, clazz);
for (ParcelableSpan parcelableSpan : spannables) {
int beginSpan = spannable.getSpanStart(parcelableSpan);
int endSpan = spannable.getSpanEnd(parcelableSpan);
if (beginSpan >= start && endSpan <= end) {
continue;
}
sub.setSpan(clone(parcelableSpan), Math.max(beginSpan - start, 0), Math.min(sub.length() - 1, endSpan), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return sub;
} else {
return charSequence.subSequence(start, end);
}
}
static CharSequence subSequence(CharSequence charSequence, int start, int end) {
if (start == 0 && charSequence.length() + 1 == end) {
return charSequence;
}
if (charSequence instanceof Spannable) {
Spannable spannable = (Spannable) charSequence;
Spannable sub = (Spannable) spannable.subSequence(start, end);
for (Class<? extends ParcelableSpan> clazz : SPAN_CLASSES) {
ParcelableSpan[] spannables = spannable.getSpans(start, end, clazz);
for (ParcelableSpan parcelableSpan : spannables) {
int beginSpan = spannable.getSpanStart(parcelableSpan);
int endSpan = spannable.getSpanEnd(parcelableSpan);
if (beginSpan >= start && endSpan <= end) {
continue;
}
sub.setSpan(clone(parcelableSpan), Math.max(beginSpan - start, 0), Math.min(sub.length() - 1, endSpan), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return sub;
} else {
return charSequence.subSequence(start, end);
}
}
private Spannable createSpan(String text, ParcelableSpan span, String[] spanTexts) {
final Spannable result = new SpannableString(text);
for (String spanText : spanTexts) {
int spanTextStart = text.indexOf(spanText);
if (spanTextStart >= 0
&& spanTextStart < text.length()
&& spanText.length() <= text.length()) {
result.setSpan(span, spanTextStart, (spanTextStart + spanText.length()),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return result;
}
@Override public void bindView(GridStoreMetaDisplayable displayable, int position) {
badgeDialogFactory = displayable.getBadgeDialogFactory();
accountManager = displayable.getAptoideAccountManager();
storeUtilsProxy = displayable.getStoreUtilsProxy();
spannableFactory = new SpannableFactory();
FragmentNavigator fragmentNavigator = getFragmentNavigator();
Resources resources = getContext().getResources();
followersCountTv.setOnClickListener(v -> {
navigateToFollowersScreen(displayable, resources, fragmentNavigator);
});
followingCountTv.setOnClickListener(
v -> navigateToFollowingScreen(displayable, fragmentNavigator, resources));
compositeSubscription.add(displayable.getHomeMeta(accountManager)
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(homeMeta -> {
ParcelableSpan[] textStyle = {
new StyleSpan(android.graphics.Typeface.BOLD),
new ForegroundColorSpan(homeMeta.getThemeColor())
};
showMainIcon(homeMeta.getMainIcon());
showSecondaryIcon(homeMeta.getSecondaryIcon());
showMainName(homeMeta.getMainName());
showSecondaryName(homeMeta.getSecondaryName());
setupActionButton(homeMeta.isShowButton(), homeMeta.isOwner(), homeMeta.getStoreId(),
homeMeta.getStoreTheme(), homeMeta.getMainName(), homeMeta.getDescription(),
homeMeta.getMainIcon(), homeMeta.isFollowingStore(), displayable.getRequestCode(),
displayable.getRaisedButtonBackground());
showAppsCount(homeMeta.getAppsCount(), textStyle, homeMeta.isShowApps(),
homeMeta.getStoreId());
showFollowersCount(homeMeta.getFollowersCount(), textStyle);
showFollowingCount(homeMeta.getFollowingCount(), textStyle);
showDescription(homeMeta.getDescription());
showBadge(homeMeta.getBadge(), homeMeta.isOwner());
})
.subscribe());
}
private void showAppsCount(long appsCount, ParcelableSpan[] textStyle, boolean showApps,
long storeName) {
if (showApps) {
appsCountTv.setVisibility(View.VISIBLE);
String count = AptoideUtils.StringU.withSuffix(appsCount);
String followingText =
String.format(getContext().getString(R.string.storehometab_short_apps), count);
appsCountTv.setText(spannableFactory.createMultiSpan(followingText, textStyle, count));
appsCountTv.setOnClickListener(v -> navigateToAppsListScreen(storeName));
} else {
appsCountTv.setVisibility(View.GONE);
}
}
public static void clear(final Editable editable) {
final int end = editable.length() - 1;
for (Class<? extends ParcelableSpan> clazz : SPAN_CLASSES) {
for (ParcelableSpan span : editable.getSpans(0, end, clazz)) {
editable.removeSpan(span);
}
}
}
private static ParcelableSpan clone(ParcelableSpan span) {
if (span instanceof ForegroundColorSpan) {
return new ForegroundColorSpan(((ForegroundColorSpan) span).getForegroundColor());
} else if (span instanceof TypefaceSpan) {
return new TypefaceSpan(((TypefaceSpan) span).getFamily());
} else if (span instanceof StyleSpan) {
return new StyleSpan(((StyleSpan) span).getStyle());
} else if (span instanceof StrikethroughSpan) {
return new StrikethroughSpan();
} else {
throw new AssertionError("Unknown Span");
}
}
private static ParcelableSpan createSpanForStyle(ImStyleParser.Style style) {
switch (style.getKeyword()) {
case "*":
return new StyleSpan(Typeface.BOLD);
case "_":
return new StyleSpan(Typeface.ITALIC);
case "~":
return new StrikethroughSpan();
case "`":
case "```":
return new TypefaceSpan("monospace");
default:
throw new AssertionError("Unknown Style");
}
}
public ParcelableSpan create(Matcher m) {
final char[] charSequence = extractMatchingRange(m);
Float proportion = calculateProportionBasedOnHeaderType(charSequence);
Float size = calculateAdjustedSize(proportion);
return new TextAppearanceSpan(highlighter.fontType, Typeface.BOLD, (int) size.byteValue(),
ColorStateList.valueOf(color), null);
}
private void createMonospaceSpanForMatches(Editable e, Pattern pattern) {
createSpanForMatches(e, pattern, new SpanCreator() {
@Override
public ParcelableSpan create(Matcher m) {
return new TypefaceSpan("monospace");
}
});
}
private void createSpanWithStrikeThroughForMatches(Editable e, Pattern pattern) {
createSpanForMatches(e, pattern, new SpanCreator() {
@Override
public ParcelableSpan create(Matcher m) {
return new StrikethroughSpan();
}
});
}
private void createStyleSpanForMatches(final Editable e, final Pattern pattern,
final int style) {
createSpanForMatches(e, pattern, new SpanCreator() {
@Override
public ParcelableSpan create(Matcher m) {
return new StyleSpan(style);
}
});
}
private void createColorSpanForMatches(final Editable e, final Pattern pattern,
final int color) {
createSpanForMatches(e, pattern, new SpanCreator() {
@Override
public ParcelableSpan create(Matcher m) {
return new ForegroundColorSpan(color);
}
});
}
public static void clear(final Editable editable) {
final int end = editable.length() - 1;
for (Class<? extends ParcelableSpan> clazz : SPAN_CLASSES) {
for (ParcelableSpan span : editable.getSpans(0, end, clazz)) {
editable.removeSpan(span);
}
}
}
private static ParcelableSpan clone(ParcelableSpan span) {
if (span instanceof ForegroundColorSpan) {
return new ForegroundColorSpan(((ForegroundColorSpan) span).getForegroundColor());
} else if (span instanceof TypefaceSpan) {
return new TypefaceSpan(((TypefaceSpan) span).getFamily());
} else if (span instanceof StyleSpan) {
return new StyleSpan(((StyleSpan) span).getStyle());
} else if (span instanceof StrikethroughSpan) {
return new StrikethroughSpan();
} else {
throw new AssertionError("Unknown Span");
}
}
private static ParcelableSpan createSpanForStyle(ImStyleParser.Style style) {
switch (style.getKeyword()) {
case "*":
return new StyleSpan(Typeface.BOLD);
case "_":
return new StyleSpan(Typeface.ITALIC);
case "~":
return new StrikethroughSpan();
case "`":
case "```":
return new TypefaceSpan("monospace");
default:
throw new AssertionError("Unknown Style");
}
}
/**
* Flatten a CharSequence and whatever styles can be copied across processes
* into the parcel.
*/
public static void writeToParcel(CharSequence cs, Parcel p,
int parcelableFlags) {
if (cs instanceof Spanned) {
p.writeInt(0);
p.writeString(cs.toString());
Spanned sp = (Spanned) cs;
Object[] os = sp.getSpans(0, cs.length(), Object.class);
// note to people adding to this: check more specific types
// before more generic types. also notice that it uses
// "if" instead of "else if" where there are interfaces
// so one object can be several.
for (int i = 0; i < os.length; i++) {
Object o = os[i];
Object prop = os[i];
if (prop instanceof CharacterStyle) {
prop = ((CharacterStyle) prop).getUnderlying();
}
if (prop instanceof ParcelableSpan) {
ParcelableSpan ps = (ParcelableSpan)prop;
// dont percel unknown span id
int id = ps.getSpanTypeId();
if ( id <= ANNOTATION ){
p.writeInt(id);
ps.writeToParcel(p, parcelableFlags);
writeWhere(p, sp, o);
}
// p.writeInt(ps.getSpanTypeId());
// ps.writeToParcel(p, parcelableFlags);
// writeWhere(p, sp, o);
}
}
p.writeInt(0);
} else {
p.writeInt(1);
if (cs != null) {
p.writeString(cs.toString());
} else {
p.writeString(null);
}
}
}
private void showFollowingCount(long followingCount, ParcelableSpan[] textStyle) {
String countText = AptoideUtils.StringU.withSuffix(followingCount);
String followingText =
String.format(getContext().getString(R.string.storehometab_short_following), countText);
followingCountTv.setText(spannableFactory.createMultiSpan(followingText, textStyle, countText));
}
private void showFollowersCount(long followersCount, ParcelableSpan[] textStyle) {
String count = AptoideUtils.StringU.withSuffix(followersCount);
String followingText =
String.format(getContext().getString(R.string.storehometab_short_subscribers), count);
followersCountTv.setText(spannableFactory.createMultiSpan(followingText, textStyle, count));
}
/**
* Logs the type, position and args of spans which attach to given text, but only if log priority
* is equal to Log.VERBOSE. Format is {type 'spanned text' extra-data} {type 'other text'
* extra-data} ..."
*
* @param text Text to be logged
*/
public static String spansToStringForLogging(CharSequence text) {
if (!LogUtils.shouldLog(Log.VERBOSE)) {
return null;
}
if (isEmptyOrNotSpannableStringType(text)) {
return null;
}
Spanned spanned = (Spanned) text;
ParcelableSpan[] spans = spanned.getSpans(0, text.length(), ParcelableSpan.class);
if (spans.length == 0) {
return null;
}
StringBuilder stringBuilder = new StringBuilder();
for (ParcelableSpan span : spans) {
stringBuilder.append("{");
// Span type.
stringBuilder.append(span.getClass().getSimpleName());
// Span text.
int start = spanned.getSpanStart(span);
int end = spanned.getSpanEnd(span);
if (start < 0 || end < 0 || start == end) {
stringBuilder.append(" invalid index:[");
stringBuilder.append(start);
stringBuilder.append(",");
stringBuilder.append(end);
stringBuilder.append("]}");
continue;
} else {
stringBuilder.append(" '");
stringBuilder.append(spanned, start, end);
stringBuilder.append("'");
}
// Extra data.
if (span instanceof LocaleSpan) {
LocaleSpan localeSpan = (LocaleSpan) span;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Locale locale = localeSpan.getLocale();
if (locale != null) {
stringBuilder.append(" locale=");
stringBuilder.append(locale);
}
} else {
LocaleList localeList = localeSpan.getLocales();
int size = localeList.size();
if (size > 0) {
stringBuilder.append(" locale=[");
for (int i = 0; i < size - 1; i++) {
stringBuilder.append(localeList.get(i));
stringBuilder.append(",");
}
stringBuilder.append(localeList.get(size - 1));
stringBuilder.append("]");
}
}
} else if (span instanceof TtsSpan) {
TtsSpan ttsSpan = (TtsSpan) span;
stringBuilder.append(" ttsType=");
stringBuilder.append(ttsSpan.getType());
PersistableBundle bundle = ttsSpan.getArgs();
Set<String> keys = bundle.keySet();
if (!keys.isEmpty()) {
for (String key : keys) {
stringBuilder.append(" ");
stringBuilder.append(key);
stringBuilder.append("=");
stringBuilder.append(bundle.get(key));
}
}
} else if (span instanceof URLSpan) {
URLSpan urlSpan = (URLSpan) span;
stringBuilder.append(" url=");
stringBuilder.append(urlSpan.getURL());
}
stringBuilder.append("}");
}
return stringBuilder.toString();
}
/**
* Flatten a CharSequence and whatever styles can be copied across processes
* into the parcel.
*/
public static void writeToParcel(CharSequence cs, Parcel p,
int parcelableFlags) {
if (cs instanceof Spanned) {
p.writeInt(0);
p.writeString(cs.toString());
Spanned sp = (Spanned) cs;
Object[] os = sp.getSpans(0, cs.length(), Object.class);
// note to people adding to this: check more specific types
// before more generic types. also notice that it uses
// "if" instead of "else if" where there are interfaces
// so one object can be several.
for (int i = 0; i < os.length; i++) {
Object o = os[i];
Object prop = os[i];
if (prop instanceof CharacterStyle) {
prop = ((CharacterStyle) prop).getUnderlying();
}
if (prop instanceof ParcelableSpan) {
ParcelableSpan ps = (ParcelableSpan)prop;
// dont percel unknown span id
int id = ps.getSpanTypeId();
if ( id <= ANNOTATION ){
p.writeInt(id);
ps.writeToParcel(p, parcelableFlags);
writeWhere(p, sp, o);
}
// p.writeInt(ps.getSpanTypeId());
// ps.writeToParcel(p, parcelableFlags);
// writeWhere(p, sp, o);
}
}
p.writeInt(0);
} else {
p.writeInt(1);
if (cs != null) {
p.writeString(cs.toString());
} else {
p.writeString(null);
}
}
}
ParcelableSpan create(Matcher m);