这篇文章讲述一下,长按文本的时候:选中文字、两个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;
}