這篇文章講述一下,長按文本的時候:選中文字、兩個selection的圖片如何加載的、複製粘貼(floatingtoolbar)如何顯示的。
一切都是從textview開始的,在textview之前的就不分析了。
一、長按文本觸發
長按文本,則必然是textview的performLongClick
@Override
public boolean performLongClick() {
boolean handled = false;
if (mEditor != null) {
mEditor.mIsBeingLongClicked = true;
}
if (super.performLongClick()) {
handled = true;
}
if (mEditor != null) {
handled |= mEditor.performLongClick(handled);//調用到editor的長按處理
mEditor.mIsBeingLongClicked = false;
}
二、核心處理:Editor中
public boolean performLongClick(boolean handled) {
// Long press in empty space moves cursor and starts the insertion action mode.根據註釋,看到,這個if裏面是處理:長按沒有文本的空白地方的處理邏輯
if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
mInsertionControllerEnabled) {//判斷點擊的位置(x,y)是否在text上
final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
mLastDownPositionY);//根據點擊位置(x,y)獲取offset位置,在Layout.java中的函數:getOffsetForHorizontal具體實現
Selection.setSelection((Spannable) mTextView.getText(), offset);//設置selection,關於selection不在詳細講述,這裏沒人改過,比較穩定。
getInsertionController().show();//這裏就是顯示圖片,所調用code。---需要後需分析A.
mIsInsertionActionModeStartPending = true;
handled = true;
}
if (!handled && mTextActionMode != null) {//選中文本範圍的邏輯
if (touchPositionIsInSelection()) {//是否有文本可以選中,有啓動拖拽;這裏也是見在左右兩個範圍圖片的邏輯。 ---需要分析B
startDragAndDrop();
} else {//拖拽不再第一次選中的文本範圍內,重新開始選擇單詞並開始拖拽
stopTextActionMode();
selectCurrentWordAndStartDrag();//初始化
}
handled = true;
}
// Start a new selection
if (!handled) {
handled = selectCurrentWordAndStartDrag();
}
return handled;
}
看一下,選中範圍的兩個圖片:分析A getInsertionController().show()
InsertionPointCursorController getInsertionController() {
...
if (mInsertionPointCursorController == null) {
mInsertionPointCursorController = new InsertionPointCursorController();//這裏new的
final ViewTreeObserver observer = mTextView.getViewTreeObserver();
observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
}
return mInsertionPointCursorController;
}
new對象是InsertionPointCursorController,那麼getInsertionController().show()就是下面這段邏輯:
public void show() {
getHandle().show();//這裏show,那麼拿圖片的邏輯肯定在getHandle裏了
...
}
private InsertionHandleView getHandle() {
if (mSelectHandleCenter == null) {
mSelectHandleCenter = mTextView.getContext().getDrawable(
mTextView.mTextSelectHandleRes);//這裏就是拿圖片了,根據名字可以看出,這裏是中間的圖片,也就是移動cursor時候使用的圖片
}
if (mHandle == null) {
mHandle = new InsertionHandleView(mSelectHandleCenter);
}
return mHandle;
}
看一下mTextSelectHandleRes的定義,在textview中
case com.android.internal.R.styleable.TextView_textSelectHandle:
mTextSelectHandleRes = a.getResourceId(attr, 0);
如果有定義主題只是: 點擊打開鏈接,就明白,這裏是style.xml中的定義
/frameworks/base/core/res/res/values/styles.xml
489 <style name="Widget.TextView">
490 <item name="textAppearance">?attr/textAppearanceSmall</item>
491 <item name="textSelectHandleLeft">?attr/textSelectHandleLeft</item>//左邊的圖片
492 <item name="textSelectHandleRight">?attr/textSelectHandleRight</item>//右邊
493 <item name="textSelectHandle">?attr/textSelectHandle</item>//這是中間的
在themes_holo.xml中
590 <!-- Text selection handle attributes -->
591 <item name="textSelectHandleLeft">@drawable/text_select_handle_left_material</item>
592 <item name="textSelectHandleRight">@drawable/text_select_handle_right_material</item>
593 <item name="textSelectHandle">@drawable/text_select_handle_middle_material</item>
這裏就可以看到圖片的定義了.
就是上面這三張。
下面分析下B,做與兩個圖片夾在的邏輯:
editor中的函數:
private boolean touchPositionIsInSelection() {
...
SelectionModifierCursorController selectionController = getSelectionController();//加載兩張圖片
...
return ((minOffset >= selectionStart) && (maxOffset < selectionEnd));
}
SelectionModifierCursorController getSelectionController() {
if (!mSelectionControllerEnabled) {
return null;
}
if (mSelectionModifierCursorController == null) {
mSelectionModifierCursorController = new SelectionModifierCursorController();
final ViewTreeObserver observer = mTextView.getViewTreeObserver();
observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
}
return mSelectionModifierCursorController;
}