RecyclerView复用EditText后长按不可选中

2024-02-28 09:18

本文主要是介绍RecyclerView复用EditText后长按不可选中,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

要想找到问题的原因就得debug,入口呢?就是上篇文章提到的selectCurrentWordAndStartDrag()这个方法

private boolean selectCurrentWordAndStartDrag() {if (mInsertionActionModeRunnable != null) {mTextView.removeCallbacks(mInsertionActionModeRunnable);}if (extractedTextModeWillBeStarted()) {return false;}if (!checkField()) {return false;}if (!mTextView.hasSelection() && !selectCurrentWord()) {// No selection and cannot select a word.return false;}stopTextActionModeWithPreservingSelection();getSelectionController().enterDrag(SelectionModifierCursorController.DRAG_ACCELERATOR_MODE_WORD);return true;}

我发现被复用的EditText在checkField()的时候返回的是false,从而导致了这个方法进行不下去了,这是问题的切入点。我们看看checkField()方法:

    /*** Checks whether a selection can be performed on the current TextView.** @return true if a selection can be performed*/boolean checkField() {if (!mTextView.canSelectText() || !mTextView.requestFocus()) {Log.w(TextView.LOG_TAG,"TextView does not support text selection. Selection cancelled.");return false;}return true;}

这个方法的作用是检测在当前的TextView中是否可以执行选中,mTextView.requestFocus()是没有问题的,问题出在mTextView.canSelectText(),于是进入到canSelectText()方法:

boolean canSelectText() {return mText.length() != 0 && mEditor != null && mEditor.hasSelectionController();
}

这个方法很简单,debug 显示mEditor.hasSelectionController()返回为false,通过上一篇文章可以知道正常情况下mEditor的SelectionController是SelectionModifierCursorController,这里为啥返回为false呢?进去看看:

boolean hasSelectionController() {return mSelectionControllerEnabled;
}

只是返回了一个变量mSelectionControllerEnabled,想必是mSelectionControllerEnabled在被复用的时候被设置为了false,搜索一下这个变量在Editor中是在哪个地方赋值的,结果发现在这个方法里:

    void prepareCursorControllers() {boolean windowSupportsHandles = false;//获取mTextView的布局属性ViewGroup.LayoutParams params = mTextView.getRootView().getLayoutParams();//如果布局属性为WindowManager.LayoutParams才能执行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;}}}

mSelectionControllerEnabled 的值取决于enabled && mTextView.textCanBeSelected(); 从debug上看 mTextView.textCanBeSelected();返回的是true,那问题就出在enabled 喽,enabled = windowSupportsHandles && mTextView.getLayout() != null; debug显示windowSupportsHandles 值为false,windowSupportsHandles 默认为false,赋值的地方就在if语句中,难道赋值为false了,还是根本就没有执行赋值语句呢?反复进行了几次debug发现都没有进入if语句中。

问题的关键来了,正常情况下mTextView.getRootView()返回的是DecorView,DecorView的LayoutParams类型就是WindowManager.LayoutParams,所以能执行if语句,被复用后的mTextView.getRootView()返回的并不是DecorView,而是EditText自己,为什么会出现这种情况呢?getRootView()这个方法是位于View中的:

public View getRootView() {if (mAttachInfo != null) {//正常情况下mAttachInfo.mRootView就是DecorViewfinal View v = mAttachInfo.mRootView;if (v != null) {return v;}}View parent = this;while (parent.mParent != null && parent.mParent instanceof View) {parent = (View) parent.mParent;}return parent;}

mAttachInfo是在AttachedToWindow的时候赋值的,结果发现mAttachInfo为空,所以才不会执行mAttachInfo.mRootView,而返回this;那么为什么mAttachInfo 为空呢,这里我没有去研究RecyclerView(懒),但可以肯定的是RecyclerView复用EditText时候没有做AttachedToWindow的操作从而导致mAttachInfo 为空。

那如何解决这个复用问题呢?不复用。卧槽,搞了半天你没有解决问题啊(不要打我啊)。目前还没有想到好的解决办法,如果有同学知道的话还请不吝赐教,这里看一下我的解决方法,在RecyclerView中的onBindViewHolder中调用holder.setIsRecyclable(false) 就可以解决问题啦!

    @Overridepublic void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {if (holder instanceof EditVH) {/* 强制关闭复用,以解决EditText被复用后长按无法弹出ContextMenu的问题 */holder.setIsRecyclable(false);} else if (holder instanceof ImgVH) {//......}}

如果是用ListView的话一样可以通过不复用convertView而解决这个问题。

这篇关于RecyclerView复用EditText后长按不可选中的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/755056

相关文章

在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

MySQL脏读、不可重复读、幻读(虚读)

事务的特性: 原子性:指处于同一个事务中的多条语句是不可分割的。一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。比如转账,转账前两个账户余额之和为2k,转账之后也应该是2K。隔离性:指多线程环境下,一个线程中的事务不能被其他线程中的事务打扰持久性:事务一旦提交,就应该被永久保存起来。 事务隔离性问题: 如果不考虑事务的隔离性,会出现以下问题: 脏读:指一个线程中的事务读取到

可重入锁和不可重入锁概念和区别

可重入锁就是一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得该锁。 这种情景,可以是不同的线程分别调用这个两个方法。也可是同一个线程,A方法中调用B方法,这个线程调用A方法。 不可重入锁就是一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得不

学习整理使用jquery实现获取相同name被选中的多选框值的方法

学习整理使用jquery实现获取相同name被选中的多选框值的方法 <html><head><meta charset="gbk"><!-- 引入JQuery --><script src="https://www.qipa250.com/jquery/dist/jquery.min.js" type="text/javascript"></script></head><body>

FPGA随记——小说 可综合和不可综合

当然我在网络上找到了些可综合和不可综合的解释 感觉也很有参考价值: https://wenda.so.com/q/1378362174074040 综合就是把你写的rtl代码转换成对应的实际电路。 比如你写代码assign a=b&c; EDA综合工具就会去元件库里拿一个二输入与门出来,然后输入端分别接上b和c,输出端接上a 假如你写了很多这样的语句 assign a=b&c; assig

Android:EditText在hint字体大小和text字体大小不一致时的设置方法

今天碰到一个需求,有一个输入框EditText,要求输入某项金额,要求在未输入文字之前,hint提示,输入文字之后显示输入的文字,要求是未输入内容时hint字体大小为14sp,输入金额之后字体大小要变成30sp。,可是EditText本身没有这个属性可以设置,怎么办呢,只有在代码中添加监听事件了: /*** 添加监听,在hint时和text时切换字体大小*/cetMoney.addTextCha

兔子--EditText去除下划线和输入字母和数字的限制

在设置密码输入框的时候,只允许输入数字和字母,设置如下属性:  android:digits="0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 设置密码不可见(显示小黑点),并去除edittext的获取到焦点时候的下划线, 设置如下:

js 控制 checkbox不选中

js 控制 checkbox不选中 $("input[name=‘myName’]").prop("checked",false);

maven项目中程序运行编译的时候出现:编码GBK的不可映射字符

由于JDK是国际版的,我们在用javac.exe编译时,编译程序首先会获得我们操作系统默认采用的编码格式(也即在编译java程序时,若我们不指定源程序文件的编码格式,JDK首先获得操作系统的file.encoding参数(它保存的就是操作系统默认的编码格式,如WIN2k,它的值为GBK),然后JDK就把我们的java源程序从file.encoding编码格式转化为JAVA内部默认的UNICODE格