最近發(fā)現(xiàn)在Android8.0之前的手機(jī)上設(shè)置Spannable無(wú)效懒构,后來(lái)調(diào)研發(fā)現(xiàn)問(wèn)題是因?yàn)閠extAllCaps屬性和Spannable沖突問(wèn)題,把textAllCaps屬性設(shè)置為false就好了胆剧。
下面是具體原因:
textAllCaps屬性會(huì)作用在 AllCapsTransformationMethod類上
這個(gè)類是用來(lái)實(shí)現(xiàn)將文字變大寫的秩霍,具體來(lái)說(shuō)是其中的getTransformation方法。
8.0之前
該方法在8.0以前的源碼是:
@Override
public CharSequence getTransformation(CharSequence source, View view) {
//省略若干無(wú)用代碼
return source.toString().toUpperCase();
}
這個(gè)方法的入?yún)⑵鋵?shí)是個(gè)Spannable對(duì)象鸽照,通過(guò)toString().toUpperCase()等操作匿垄,返回對(duì)象變成了String归粉, 丟掉了很多我們所期望的特效(刪除線漏峰、背景色、圖片等)
8.0之后
在8.0以后的源碼中該方法改為返回Spannable
以8.1版本的源碼為例
可以直接略過(guò)下面兩塊代碼看結(jié)論
@Override
public CharSequence getTransformation(@Nullable CharSequence source, View view) {
if (!mEnabled) {
Log.w(TAG, "Caller did not enable length changes; not transforming text");
return source;
}
if (source == null) {
return null;
}
Locale locale = null;
if (view instanceof TextView) {
locale = ((TextView)view).getTextLocale();
}
if (locale == null) {
locale = mLocale;
}
final boolean copySpans = source instanceof Spanned;
return TextUtils.toUpperCase(locale, source, copySpans);
}
TextUtils的toUpperCase方法源碼如下:
public static CharSequence toUpperCase(@Nullable Locale locale, @NonNull CharSequence source,
boolean copySpans) {
final Edits edits = new Edits();
if (!copySpans) { // No spans. Just uppercase the characters.
final StringBuilder result = CaseMap.toUpper().apply(
locale, source, new StringBuilder(), edits);
return edits.hasChanges() ? result : source;
}
final SpannableStringBuilder result = CaseMap.toUpper().apply(
locale, source, new SpannableStringBuilder(), edits);
if (!edits.hasChanges()) {
// No changes happened while capitalizing. We can return the source as it was.
return source;
}
final Edits.Iterator iterator = edits.getFineIterator();
final int sourceLength = source.length();
final Spanned spanned = (Spanned) source;
final Object[] spans = spanned.getSpans(0, sourceLength, Object.class);
for (Object span : spans) {
final int sourceStart = spanned.getSpanStart(span);
final int sourceEnd = spanned.getSpanEnd(span);
final int flags = spanned.getSpanFlags(span);
// Make sure the indices are not at the end of the string, since in that case
// iterator.findSourceIndex() would fail.
final int destStart = sourceStart == sourceLength ? result.length() :
toUpperMapToDest(iterator, sourceStart);
final int destEnd = sourceEnd == sourceLength ? result.length() :
toUpperMapToDest(iterator, sourceEnd);
result.setSpan(span, destStart, destEnd, flags);
}
return result;
}
發(fā)現(xiàn)沒(méi)!在8.1版本中不再是簡(jiǎn)單的toString席噩、toUpperCase贤壁,它會(huì)將之前的Span信息存取下來(lái),返回的時(shí)候也會(huì)一并返回回去馒索,這樣下來(lái)TextView就可以根據(jù)這些返回的Span信息來(lái)給文本設(shè)置各種特效了名船。
友情提示
剛剛看了下androidx的包,發(fā)現(xiàn)也是簡(jiǎn)單的toString蜈块、toUpperCase迷扇,所以使用的時(shí)候需要注意。