從SetText()中學(xué)android(二)

關(guān)于調(diào)度器

我們?cè)陂L(zhǎng)按edittext导街,或者在設(shè)置了textview的setTextIsSelectable(true)的時(shí)候,會(huì)蹦出來一個(gè)顯示復(fù)制|粘貼|全選的窗口航棱,類似這樣

調(diào)度器

關(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è)接口

Paste_Image.png

這段話的意思是:這是一個(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) SubscriptSpanSuperscriptSpan
  • 設(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();

參考博客:http://www.liuguangli.win/archives/476http://blog.csdn.net/flowingflying/article/details/9950797https://developer.android.com/reference/android/text/method/TransformationMethod.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末令野,一起剝皮案震驚了整個(gè)濱河市舀患,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌气破,老刑警劉巖聊浅,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異现使,居然都是意外死亡狗超,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門朴下,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苦蒿,你說我怎么就攤上這事殴胧。” “怎么了佩迟?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵团滥,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我报强,道長(zhǎng)灸姊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任秉溉,我火速辦了婚禮力惯,結(jié)果婚禮上碗誉,老公的妹妹穿的比我還像新娘。我一直安慰自己父晶,他們只是感情好哮缺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著甲喝,像睡著了一般尝苇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埠胖,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天糠溜,我揣著相機(jī)與錄音,去河邊找鬼直撤。 笑死非竿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谊惭。 我是一名探鬼主播汽馋,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼圈盔!你這毒婦竟也來了豹芯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤驱敲,失蹤者是張志新(化名)和其女友劉穎铁蹈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體众眨,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡握牧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了娩梨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沿腰。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖狈定,靈堂內(nèi)的尸體忽然破棺而出颂龙,到底是詐尸還是另有隱情,我是刑警寧澤纽什,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布措嵌,位于F島的核電站,受9級(jí)特大地震影響芦缰,放射性物質(zhì)發(fā)生泄漏企巢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一让蕾、第九天 我趴在偏房一處隱蔽的房頂上張望浪规。 院中可真熱鬧或听,春花似錦、人聲如沸罗丰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萌抵。三九已至找御,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绍填,已是汗流浹背霎桅。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留讨永,地道東北人滔驶。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像卿闹,于是被迫代替她去往敵國(guó)和親揭糕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,161評(píng)論 25 707
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程锻霎,因...
    小菜c閱讀 6,424評(píng)論 0 17
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,762評(píng)論 22 665
  • 今天7點(diǎn)就被嬸嬸給叫醒了著角,今天親戚家做的房子封頂,叔叔和嬸嬸老早就起來了旋恼,然后到我樓下叫我吏口。妹妹和叔叔去...
    天空藍(lán)上閱讀 164評(píng)論 0 0
  • 該方法主要用于將 UIColor 轉(zhuǎn)化為 UIImage ,用于項(xiàng)目中冰更,放在代碼塊中产徊,方便使用
    Ice丶澤閱讀 206評(píng)論 0 0