- 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 就被保存起来了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论