關(guān)于調(diào)度器
我們?cè)陂L(zhǎng)按edittext导街,或者在設(shè)置了textview的setTextIsSelectable(true)的時(shí)候,會(huì)蹦出來一個(gè)顯示復(fù)制|粘貼|全選的窗口航棱,類似這樣
關(guān)閉選擇調(diào)度器后骇两,這個(gè)將不會(huì)顯示宴咧,同理朝群,在一個(gè)edittext中燕耿,我們可以移動(dòng)光標(biāo)位置來決定輸入位置,這是通過插入調(diào)度器來決定的
handleView是一個(gè)Editor內(nèi)部的實(shí)現(xiàn)了TextViewPositionListener接口的私有抽象類姜胖,暫不做分析
hideInsertionPointCursorController();
//執(zhí)行到這里誉帅,將控制器隱藏了
if (mInsertionPointCursorController != null) {
//@link Editor#InsertionPointCursorController#onDetached
mInsertionPointCursorController.onDetached();
mInsertionPointCursorController = null;
//先將控制器hide,如果控制器不為null谭期,直接回收掉
}
}
//同上堵第,套路都是一樣的
if (!mSelectionControllerEnabled) {
stopTextActionMode();
if (mSelectionModifierCursorController != null) {
mSelectionModifierCursorController.onDetached();
mSelectionModifierCursorController = null;
}
}
}
Editor#isCursorVisible
boolean textCanBeSelected() {
// prepareCursorController() relies on this method.
// If you change this condition, make sure prepareCursorController is called anywhere
// the value of this condition might be changed.
if (mMovement == null || !mMovement.canSelectArbitrarily())
return false;
return isTextEditable() || (isTextSelectable() && mText instanceof Spannable && isEnabled());
}
Editor#onDetached
public void onDetached() {
final ViewTreeObserver observer = mTextView.getViewTreeObserver();
observer.removeOnTouchModeChangeListener(this);
if (mHandle != null)
mHandle.onDetached();
}
view#requestLayout()
從源碼注釋可以看出,如果當(dāng)前View在請(qǐng)求布局的時(shí)候隧出,View樹正在進(jìn)行布局流程的話踏志,該請(qǐng)求會(huì)延遲到布局流程完成后或者繪制流程完成且下一次布局發(fā)現(xiàn)的時(shí)候再執(zhí)行。
總的來說胀瞪,當(dāng)view需要重新布局時(shí)調(diào)用此方法
public void requestLayout() {
if (mMeasureCache != null) mMeasureCache.clear();
if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
// Only trigger request-during-layout logic if this is the view requesting it,
// not the views in its parent hierarchy
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null && viewRoot.isInLayout()) {
if (!viewRoot.requestLayoutDuringLayout(this)) {
return;
}
}
mAttachInfo.mViewRequestingLayout = this;
}
mPrivateFlags |= PFLAG_FORCE_LAYOUT;
//需要重新布局
mPrivateFlags |= PFLAG_INVALIDATED;
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
//使用父類的requestLayout针余,父類也設(shè)置標(biāo)記位,這樣層層上傳凄诞,直到根view圆雁,然后根view傳遞給ViewRootImpl
}
if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
mAttachInfo.mViewRequestingLayout = null;
}
}
invalidate
public void invalidate() { invalidate(true); }
void invalidate(boolean invalidateCache) {
invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
}
這里遍歷mFilters,inputFilter是用于屏蔽某些字的接口帆谍,這里伪朽,我們將text輪流放置于filter中,遍歷整個(gè)數(shù)組汛蝙,最后得出text即為我們所要的text
int n = mFilters.length; for (int i = 0; i < n; i++) {
CharSequence out = mFilters[i].filter(text, 0, text.length(), EMPTY_SPANNED, 0, 0);
if (out != null) {
text = out;
}
}
重新回到settext函數(shù)>notifyBefore烈涮,會(huì)遍歷你的textwatcher的list,然后回調(diào)函數(shù)beforeTextChanged
if (notifyBefore) {
if (mText != null) {
oldlen = mText.length();
sendBeforeTextChanged(mText, 0, oldlen, text.length());
}else {
sendBeforeTextChanged("", 0, 0, text.length());
}
}
控制是否需要在text改變后通知窖剑,默認(rèn)不通知
boolean needEditableForNotification = false; //是否需要通知
if (mListeners != null && mListeners.size() != 0) {
//mListeners為textwatcher(text的觀察者坚洽,在text改變后作出回調(diào))的鏈表
//如果text有觀察者,則在改變后會(huì)作出相應(yīng)
needEditableForNotification = true; }
if (type == BufferType.EDITABLE || getKeyListener() != null || needEditableForNotification){
//getKeyListener返回的是當(dāng)前textview所對(duì)應(yīng)的Editor的keylistener
關(guān)于
keyListener
西土,keyListener是android.text.method包中的一個(gè)接口
這段話的意思是:這是一個(gè)用來基于可編輯的類讶舰,將text的key事務(wù)轉(zhuǎn)換成可編輯的操作。注意需了,在大多數(shù)情況下該接口已被一般軟輸入方法所取代跳昼,如android.view.inputmethod.InputMethod,它應(yīng)該只用于其中應(yīng)用程序有它自己的屏幕上的鍵盤援所,也希望處理硬鍵盤事件庐舟,與之相匹配的情況。>軟鍵盤上的按鍵不會(huì)觸發(fā)這個(gè)方法住拭,android4.1或之后版本的鍵盤將不會(huì)觸發(fā)挪略。在android4.0或之前的版本來提供按鍵历帚。
createEditorIfNeeded();//如果mEditor為null,創(chuàng)建一個(gè)Editor
mEditor.forgetUndoRedo();//將撤銷和重新編輯全部取消
Editable t = mEditableFactory.newEditable(text);
text = t; //使用filter來過濾Editable對(duì)象t
setFilters(t, mFilters);
InputMethodManager imm = InputMethodManager.peekInstance(); //檢索全局的InputMethodManager是否存在
InputMethodManager是一個(gè)管理輸入法面板的類
//InputMethodManager如果已經(jīng)連接了某一個(gè)view杠娱,則重新啟動(dòng)輸入法挽牢。
if (imm != null){
imm.restartInput(this);
} else if (type == BufferType.SPANNABLE || mMovement != null) {
text = mSpannableFactory.newSpannable(text);
} else if (!(text instanceof CharWrapper)) {
text = TextUtils.stringOrSpannedString(text);
} //對(duì)text的處理
if (mAutoLinkMask != 0) {
mAutoLinkMask-->自動(dòng)鏈接(如归苍,text中有網(wǎng)址鏈接喷户,自動(dòng)標(biāo)識(shí))
Spannable s2;//首先聲明一個(gè)Spannable
我們可以通過Spannable的實(shí)現(xiàn)類SpannableString來設(shè)置textview的各種樣式
使用spannablestring的setSpan(Object what, int start, int end, int flags)便可以對(duì)textview設(shè)置想要的效果。其中what共有幾種:
- 樣式 TypefaceSpan
- 絕對(duì)大小 AbsoluteSizeSpan(可以使用px或者dp)
- 相對(duì)大小RelativeSizeSpan(當(dāng)前字體的多少倍)
- 前景色和字體背景色 ForegroundColorSpan
- 設(shè)置字體的粗體晕窑,斜體室叉,粗斜體 StyleSpan
- 設(shè)置下劃線和刪除線 UnderlineSpan睹栖,StrikethroughSpan
- 設(shè)置下標(biāo)和上標(biāo) SubscriptSpan,SuperscriptSpan
- 設(shè)置超鏈接 URLSpan(需要添加setMovementMethod方法來附加相應(yīng))* 橫向拉伸字體 ScaleXSpan
if (type == BufferType.EDITABLE || text instanceof Spannable) {
s2 = (Spannable) text;
} else {
s2 = mSpannableFactory.newSpannable(text);
} if (Linkify.addLinks(s2, mAutoLinkMask)) {
text = s2;
type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;
//如果type不是BufferType.EDITABLE 則將其改為BufferType.SPANNABLE
mText = text;
if (mLinksClickable && !textCanBeSelected()) {
setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
樣式設(shè)置完成
TransformationMehods是這樣一個(gè)類茧痕,textview可以使用它來做如用替換密碼野来,或者保持新的被換行符拆分開的行
而getTransformation獲得的是源文本資源的轉(zhuǎn)換(例如:用來替換密碼,返回的長(zhǎng)度和原來的長(zhǎng)度必須相符合踪旷。如果以前的文本是Editable曼氛,則返回的必須是反應(yīng)其動(dòng)態(tài)的,不能僅僅做一次復(fù)制)
mBufferType = type;
mText = text;
//將text和type都存起來
if (mTransformation == null) {
mTransformed = text;
} else {
mTransformed = mTransformation.getTransformation(text, this);
}
final int textLength = text.length();
//記錄下textLength的長(zhǎng)度
if (text instanceof Spannable && !mAllowTransformationLengthChange) {
Spannable sp = (Spannable) text;
// 移除所有可能來自其他textview的changewatcher
final ChangeWatcher[] watchers = sp.getSpans(0, sp.length(), ChangeWatcher.class);
final int count = watchers.length;
for (int i = 0; i < count; i++) {
sp.removeSpan(watchers[i]);
}
if (mChangeWatcher == null)
mChangeWatcher = new ChangeWatcher();
sp.setSpan(mChangeWatcher, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE | (CHANGE_WATCHER_PRIORITY << Spanned.SPAN_PRIORITY_SHIFT));
if (mEditor != null)
mEditor.addSpanWatchers(sp);
if (mTransformation != null) {
sp.setSpan(mTransformation, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
if (mMovement != null) {
mMovement.initialize(this, (Spannable) text);
if (mEditor != null)
mEditor.mSelectionMoved = false;
}
}
if (mLayout != null) {
checkForRelayout();
}
sendOnTextChanged(text, 0, oldlen, textLength);
onTextChanged(text, 0, oldlen, textLength);
notifyViewAccessibilityStateChangedIfNeeded(AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
if (needEditableForNotification) {
sendAfterTextChanged((Editable) text);
}
// SelectionModifierCursorController depends on textCanBeSelected, which depends on text
if (mEditor != null)
mEditor.prepareCursorControllers();