EditText除了光标外还有选中时的左右下标以及点击某个字符位置时的插入下标,分别为SelectionHandleView 和 InsertionHandleView, 见Editor类。
Cursor
SelectionHandleView:
InsertionHandleView:
cursor对应的图片可以通过style定制:
com.android.internal.R.styleable.TextView_textCursorDrawable
SelectionHandleView有左右两个,显示流程如下
SelectionHandleView 继承自HandleView, HandleView是一个PopupWindow.
1. 左右光标的图标可以分别由以下两个style来自定义:
com.android.internal.R.styleable.TextView_textSelectHandleLeft
com.android.internal.R.styleable.TextView_textSelectHandleRight
2. 其中View的宽度和高度取图片本身的大小和com.android.internal.R.dimen.text_handle_min_size中小的那个值。
3. SelectionHandleView的显示、隐藏及刷新是由SelectionModifierCursorController来控制
4. SelectionHandleView 是否显示取决于以下方法中的两个条件:
条件1:
ViewGroup.LayoutParams params = mTextView.getRootView().getLayoutParams(); if (params instanceof WindowManager.LayoutParams) { WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params; windowSupportsHandles = windowParams.type < WindowManager.LayoutParams.FIRST_SUB_WINDOW || windowParams.type > WindowManager.LayoutParams.LAST_SUB_WINDOW; }条件2:
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()); }其中 isTextSelectable()是public方法,可以由 setTextIsSelectable 或者
android.R.styleable#TextView_textIsSelectable 来设置
5. SelectionActionMode 是指长按选中TextView的文本时的行为,实现类:TextActionModeCallback,继承自ActionMode.CallBack2(实现了ActionMode.CallBack接口)。
TextView中长按选中TextView文本时的行为默认是弹出的悬浮菜单,用户可以通过下列方法自定义行为:
/** * If provided, this ActionMode.Callback will be used to create the ActionMode when text * selection is initiated in this View. * * The standard implementation populates the menu with a subset of Select All, Cut, Copy, * Paste, Replace and Share actions, depending on what this View supports. * * A custom implementation can add new entries in the default menu in its * {@link android.view.ActionMode.Callback#onPrepareActionMode(ActionMode, android.view.Menu)} * method. The default actions can also be removed from the menu using * {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll}, * {@link android.R.id#cut}, {@link android.R.id#copy}, {@link android.R.id#paste}, * {@link android.R.id#replaceText} or {@link android.R.id#shareText} ids as parameters. * * Returning false from * {@link android.view.ActionMode.Callback#onCreateActionMode(ActionMode, android.view.Menu)} * will prevent the action mode from being started. * * Action click events should be handled by the custom implementation of * {@link android.view.ActionMode.Callback#onActionItemClicked(ActionMode, * android.view.MenuItem)}. * * Note that text selection mode is not started when a TextView receives focus and the * {@link android.R.attr#selectAllOnFocus} flag has been set. The content is highlighted in * that case, to allow for quick replacement. */ public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) { createEditorIfNeeded(); mEditor.mCustomSelectionActionModeCallback = actionModeCallback; }
且如果用户自定义的callback中的
onCreateActionMode返回为false,那么久不会有悬浮菜单栏出现,也会推出选中模式。
@Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { mode.setTitle(null); mode.setSubtitle(null); mode.setTitleOptionalHint(true); populateMenuWithItems(menu); Callback customCallback = getCustomCallback(); if (customCallback != null) { if (!customCallback.onCreateActionMode(mode, menu)) { // The custom mode can choose to cancel the action mode, dismiss selection. Selection.setSelection((Spannable) mTextView.getText(), mTextView.getSelectionEnd()); return false; } }
............................
InsertionHandleView同样继承自HandleView。它在一定时间后会自动消失。它同样对应一个controller:
InsertionPointCursorController
1. InsertionHandleView 是否显示上述条件1还取决于以下方法中的条件:
boolean isCursorVisible() { // The default value is true, even when there is no associated Editor return mCursorVisible && mTextView.isTextEditable(); }
由此可以看出,只要cursor显示,就能显示InsertionHandleView.反之,没有办法只显示cursor而不显示InsertionHandleView, 除非TextView所在的RootView的窗口类型事子窗口类型,也即:既不是应用程序窗口(如Activity)也不是者系统窗口。窗口类型的说明见:android 窗口类型分析。
2. 同样用户可以通过setCustomInsertionActionModeCallback 来自定义输入状态时的行为。