text Android Edittext长按没有弹出上下文菜单

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了text Android Edittext长按没有弹出上下文菜单相关的知识,希望对你有一定的参考价值。

Android Edittext 长按没有弹出上下文菜单
2017年09月28日 19:48:00 weixin_34392906 阅读数:27
问题件简述
当 RecycleView 中有 EditText 的时候,上下滚动被复用的时候,发现长按 EditText 没有弹出上下文菜单

分析
调试了一波后发现,正常情况下长按的时候 TextView 的 performClick() 函数返回的是 true,没有弹出上下文的时候,此函数返回了 fasle

首先找 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);
        mEditor.mIsBeingLongClicked = false;
    }
 
    if (handled) {
        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        if (mEditor != null) mEditor.mDiscardNextActionUp = true;
    }
 
    return handled;
}
先正常调试

super.performLongClick() 返回 false
mEditor.performLongCLick() 返回 true
无法弹出菜单的时候调试

super.performLongClick() 返回 false
mEdit.performLongClick() 返回 false
那么问题出现在 mEdit.performLongClick() 上面,查看源码

public boolean performLongClick(boolean handled) {
    // Long press in empty space moves cursor and starts the insertion action mode.
    if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
            mInsertionControllerEnabled) {
        final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
                mLastDownPositionY);
        Selection.setSelection((Spannable) mTextView.getText(), offset);
        getInsertionController().show();
        mIsInsertionActionModeStartPending = true;
        handled = true;
    }
    // 此处省略一些代码...
    return handled;
}
正常调试

mInsertionControllerEnabled 是 true
无法弹出菜单时候的调试

mInsertionControllerEnable 为 false
那么问题定位到 mInsertionControllerEnabled 的布尔值了,寻找这个成员属性被修改的地方,发现在 Editor#prepareCursorControllers 内,查看源码

void prepareCursorControllers() {
    boolean windowSupportsHandles = false;
 
    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;
    }
 
    boolean enabled = windowSupportsHandles && mTextView.getLayout() != null;
    mInsertionControllerEnabled = enabled && isCursorVisible();
    mSelectionControllerEnabled = enabled && mTextView.textCanBeSelected();
 
    if (!mInsertionControllerEnabled) {
        hideInsertionPointCursorController();
        if (mInsertionPointCursorController != null) {
            mInsertionPointCursorController.onDetached();
            mInsertionPointCursorController = null;
        }
    }
 
    if (!mSelectionControllerEnabled) {
        stopTextActionMode();
        if (mSelectionModifierCursorController != null) {
            mSelectionModifierCursorController.onDetached();
            mSelectionModifierCursorController = null;
        }
    }
}
到这里不用调试就可以看出问题出在哪里 ViewGroup.LayoutParams params = mTextView.getRootView().getLayoutParams(); 这句话,如果在 ViewHolder 绑定数据的时候被执行的话,永远不可能是 WindowManager.LayoutParams,因为此时 EdtiText 根本没有被 attachToWindow

解决方案
既然知道了是 EditText 没有被 attachToWindow 的时候调用了 Editor#prepareCursorControllers 函数导致的,那么我在 attachToWindow 之后重新调用一遍这个函数不就可以了?

因为这个是包权限的方法,所以需要找间接调用的地方,找到了 setCursorVisible 方法中有被调用,所以只要在 onAttachToWindow 的时候先设置成 false 然后再设置成 true 就可以了

edtImgDesc.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
     @Override
     public void onViewAttachedToWindow(View v) {
         edtImgDesc.setCursorVisible(false);
         edtImgDesc.setCursorVisible(true);
     }
 
     @Override
     public void onViewDetachedFromWindow(View v) {
     }
 })

以上是关于text Android Edittext长按没有弹出上下文菜单的主要内容,如果未能解决你的问题,请参考以下文章

Android:EditText长按选词的过程

android自定义edittext 当有文字时怎么禁止长按全选事件

Android的EditText长按只显示上面的复制粘贴菜单,不要弹出下面的输入法键盘怎么做?

Android 的某些 EditText 字段不响应长按(API 30+ with layout_width 0dp)

android如何禁止edittext复制粘贴

EditText android:text 设置的默认值运行的时候为空并且不能滚动