- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
2.1 SpannableString
SpannableString 是由一个内部 SpannableStringInternal 实现的,所以我们就直接看 SpannableStringInternal 源码:
/* package */
void setSpan(Object what, int start, int end, int flags) {
int nstart = start;
int nend = end;
// 检查 start 和 end 是否合法
checkRange("setSpan", start, end);
// 对 SPAN_PARAGRAPH 做格式检查
if ((flags & Spannable.SPAN_PARAGRAPH) == Spannable.SPAN_PARAGRAPH) {
if (start != 0 && start != length()) {
char c = charAt(start - 1);
if (c != '\n')
throw new RuntimeException(
"PARAGRAPH span must start at paragraph boundary" +
" (" + start + " follows " + c + ")");
}
if (end != 0 && end != length()) {
char c = charAt(end - 1);
if (c != '\n')
throw new RuntimeException(
"PARAGRAPH span must end at paragraph boundary" +
" (" + end + " follows " + c + ")");
}
}
// 检查是否已经存在 span
int count = mSpanCount;
Object[] spans = mSpans;
int[] data = mSpanData;
for (int i = 0; i < count; i++) {
if (spans[i] == what) {
int ostart = data[i * COLUMNS + START];
int oend = data[i * COLUMNS + END];
data[i * COLUMNS + START] = start;
data[i * COLUMNS + END] = end;
data[i * COLUMNS + FLAGS] = flags;
sendSpanChanged(what, ostart, oend, nstart, nend);
return;
}
}
// 检查数组大小
if (mSpanCount + 1 >= mSpans.length) {
Object[] newtags = ArrayUtils.newUnpaddedObjectArray(
GrowingArrayUtils.growSize(mSpanCount));
int[] newdata = new int[newtags.length * 3];
System.arraycopy(mSpans, 0, newtags, 0, mSpanCount);
System.arraycopy(mSpanData, 0, newdata, 0, mSpanCount * 3);
mSpans = newtags;
mSpanData = newdata;
}
mSpans[mSpanCount] = what;
mSpanData[mSpanCount * COLUMNS + START] = start;
mSpanData[mSpanCount * COLUMNS + END] = end;
mSpanData[mSpanCount * COLUMNS + FLAGS] = flags;
mSpanCount++;
if (this instanceof Spannable)
sendSpanAdded(what, nstart, nend);
}首先是通过 checkRange 方法检查 start 和 end 是否合法:
private void checkRange(final String operation, int start, int end) {
if (end < start) {
throw new IndexOutOfBoundsException(operation + " " +
region(start, end) +
" has end before start");
}
int len = length();
if (start > len || end > len) {
throw new IndexOutOfBoundsException(operation + " " +
region(start, end) +
" ends beyond length " + len);
}
if (start < 0 || end < 0) {
throw new IndexOutOfBoundsException(operation + " " +
region(start, end) +
" starts before 0");
}
}接下来检查是否是 SPAN_PARAGRAPH, 当 flag 是 SPAN_PARAGRAPH 时, start 和 end 必须要是字符串的开头和结尾,例如:
SpannableString ss = new SpannableString("abcd");
ss.setSpan(new UnderlineSpan(), 0,4, Spanned.SPAN_PARAGRAPH);然后会检查是否已经存在了相同的 span 对象,如果已经存在相同的 span, 那么就会用新的覆盖旧的,所以在使用的时候要注意不要使用同一个对象:
SpannableString ss = new SpannableString("abcd");
UnderlineSpan underlineSpan = new UnderlineSpan();
ss.setSpan(underlineSpan, 1,2, Spanned.SPAN_INCLUSIVE_INCLUSIVE); // 这个被覆盖了
ss.setSpan(underlineSpan, 3,4, Spanned.SPAN_INCLUSIVE_INCLUSIVE);然后检查数组大小,不够大时扩容,最终将值保存起来,保存的方式也很容易理解,如下代码所示:
private static final int START = 0; private static final int END = 1; private static final int FLAGS = 2; private static final int COLUMNS = 3; mSpans[mSpanCount] = what; mSpanData[mSpanCount * COLUMNS + START] = start; mSpanData[mSpanCount * COLUMNS + END] = end; mSpanData[mSpanCount * COLUMNS + FLAGS] = flags; mSpanCount++;
到这里为止,我们的 span 就被保存起来了。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论