【问题标题】:"android:textIsSelectable="true" not working for TextView in RecyclerView“android:textIsSelectable="true" 不适用于 RecyclerView 中的 TextView
【发布时间】:2016-04-22 19:02:27
【问题描述】:

我知道在TextView 的xml 中设置android:textIsSelectable="true" 将显示本机文本选择弹出窗口,我一直在我的应用程序中使用它。但是当我尝试在附加到RecyclerView 的视图中设置相同的属性时,我发现它不再起作用了。 每当我尝试选择文本时,都会出现以下日志 -

TextView: TextView does not support text selection. Action mode cancelled.

我不知道为什么?为什么它适用于其他屏幕而不适用于RecyclerView。我阅读了多篇文章-

TextView with android:textIsSelectable="true" not working in listview

textview textIsSelectable="true" not working in Listview

android:textIsSelectable="true" for TextView inside Listview does not work

但后来我遇到了这个帖子-

Android: "TextView does not support text selection. Action mode cancelled"

@hungkk 的回复对我有用。他的解决方案建议将TextView 宽度从match_parent 更改为wrap_content

我知道我可以做到这一点,但我的问题是这如何解决问题,因为它对我来说看起来很奇怪。另外,如果我想保持宽度为match_parent,解决方案是什么。

欢迎提出任何意见。

【问题讨论】:

  • 你在做什么选择? (马蒂或沙达布)。我对match_parentwrap_content 使用View.OnClickListener() 没有任何问题。
  • 奇怪,但我在一些帖子中读到,当回收者的视图重用单元格时,如果 TextView 设置为 match_parent,它会禁用可选文本功能。您是否尝试过设置android:inputType="textMultiLine"' 而不是android:textIsSelectable="true" 作为解决方法?

标签: android android-recyclerview textview


【解决方案1】:

在recyclerview的主父布局中添加属性

android:descendantFocusability="beforeDescendants"

然后在rowitem布局的TextView中添加

android:textIsSelectable="true"

【讨论】:

    【解决方案2】:

    我发现RecyclerView中的TextView第一次可以选择,但是当ViewHolder被回收或适配器notifyDataSetChanged时,所有的文本视图都不能被选择。 我发现这个解决方案对我有用。

    yourTextView.setText("your text");
    yourTextView.setTextIsSelectable(false);
    yourTextView.measure(-1, -1);//you can specific other values.
    yourTextView.setTextIsSelectable(true);
    

    为什么要这样做?因为我在android源码中调试过,发现了一些逻辑:

    TextView.java:

    public void setTextIsSelectable(boolean selectable) {
        if (!selectable && mEditor == null) return; // false is default value with no edit data
    
        createEditorIfNeeded();
        if (mEditor.mTextIsSelectable == selectable) return;
    
        mEditor.mTextIsSelectable = selectable;
        setFocusableInTouchMode(selectable);
        setFocusable(FOCUSABLE_AUTO);
        setClickable(selectable);
        setLongClickable(selectable);
    
        // mInputType should already be EditorInfo.TYPE_NULL and mInput should be null
    
        setMovementMethod(selectable ? ArrowKeyMovementMethod.getInstance() : null);
        setText(mText, selectable ? BufferType.SPANNABLE : BufferType.NORMAL);
    
        // Called by setText above, but safer in case of future code changes
        mEditor.prepareCursorControllers();
    }
    

    Editor.java

    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;
            }
        }
    }
    

    ---> TextView.java

    /**
     * Test based on the <i>intrinsic</i> charateristics of the TextView.
     * The text must be spannable and the movement method must allow for arbitary selection.
     *
     * See also {@link #canSelectText()}.
     */
    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());
    }
    

    您可以在模拟器中调试并跟踪此代码。

    【讨论】:

    • 哇,如果可以的话,我会给你 100 个加分。经过数小时的搜索和尝试,这是唯一对我有用的解决方案。许多解决方案在较旧或较新的 android 版本上都不起作用或有奇怪的副作用。但这解决了我在 android 6 和 10 的列表视图中的大型文本视图的问题。
    • 可以确认这也适用于我,似乎根本问题仍未解决issuetracker.google.com/issues/37095917
    • 另一个合适更好的解决方案是fun TextView.fixTextSelection() { setTextIsSelectable(false) post { setTextIsSelectable(true) } }
    【解决方案3】:

    如果您在recyclerviewlistview 中添加android:descendantFocusability="blocksDescendants"​,则将其删除。 并在检查后

    【讨论】:

      【解决方案4】:
      override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
          yourTextView.fixTextSelection()
      }
      
      fun TextView.fixTextSelection() {
          setTextIsSelectable(false)
          post { setTextIsSelectable(true) }
      }
      

      【讨论】:

      • 这救了我!比上述measure 解决方案要好得多。
      【解决方案5】:

      添加你的 RecyclerView 适配器:

      public ViewHolder(View itemView) {
                  super(itemView);
                  txtDate = (TextView) itemView.findViewById(R.id.txtDate);
                  txtDate.setTextIsSelectable(true);
      }
      

      它对我有用..

      【讨论】:

        【解决方案6】:

        似乎有很多人对此有问题,并表明这可能是 Android 代码中的错误,但我没有问题。这对OnClickListener() 和本机选择弹出窗口都适用。 (在 KitKat 4.4、Lollipop 5.1 和 Nougat 7.1 上测试)

        在适配器中

        class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
            TextView textView;
            ImageView imageView;
        
            MyViewHolder(View itemView) {
                super(itemView);
                textView = (TextView) itemView.findViewById(R.id.my_text_view);
                imageView = (ImageView) itemView.findViewById(R.id.my_image_view);
        
                itemView.setOnClickListener(this);
                textView.setOnClickListener(this);
            }
        
            @Override
            public void onClick(View view) {
                // this shows 'my_text_view' when the text is clicked or 
                //     'my_item' if elsewhere is clicked
                Log.d(TAG, "view = " + view.toString());
                switch (view.getId()) {
                    case R.id.my_item:
                        break;
                    case R.id.my_text_view:
                        break;
                }
            }
        }
        

        还有我的项目布局

        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/my_item"
            >
        
            <ImageView
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:background="@color/colorPrimary"
                android:id="@+id/my_image_view"
                />
        
            <!-- this works for me with either "match_parent" or "wrap_content" for width -->
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="20dp"
                android:text="My text view"
                android:textIsSelectable="true"
                android:id="@+id/my_text_view"
                />
        </LinearLayout>
        

        【讨论】:

          【解决方案7】:

          如果您的TextViewConstraintLayout 内,请确保宽度不是wrap_content。使用 TextView 宽度 0dpmatch_parent 可以正常工作。

          【讨论】:

            【解决方案8】:

            我发现我必须在一段时间后设置TextView 文本及其宽度。所以我把这个属性(android:textIsSelectable="true")放在TextViewpost{}的xml布局中,recyclerView适配器的onBindViewHolder方法中的宽度和文本如下:

            class ContentAdapter(): ListAdapter<Verse, ContentAdapter.ViewHolder>(DiffCallback()) {
                .
                .
                .
                override fun onBindViewHolder(holder: ViewHolder, position: Int) {
                        val item = getItem(position)
                        holder.bind(item)
                }
            
                class ViewHolder(val binding: ItemBinding): RecyclerView.ViewHolder(binding.root) {
            
                    fun bind(item: Verse){
                        binding.myTextView.apply{
                            val params = layoutParams as ConstraintLayout.LayoutParams
                            params.width = 100 /*any value you want for the width of your TextView*/
                            post{
                                layoutParams = params
                                text = item.text
                            }
                        }
                    }
            
                    companion object {
                        fun from(parent: ViewGroup): ViewHolder{
                            val layoutInflater = LayoutInflater.from(parent.context)
                            val binding = ItemBinding.inflate(layoutInflater, parent, false)
                            return ViewHolder(binding)
                        }
                    }
                }
            
            }
            

            【讨论】:

              【解决方案9】:

              最终可行的解决方案

              在你的 onBindView 中这样写你的代码!

                  textView.text = "the content"
              
                  textView.setTextIsSelectable(false)
                  textView.post { txtContent.setTextIsSelectable(true) }
              

              或者进阶版可以在TextView上写扩展函数

              fun TextView.fixTextSelection(){
                 setTextIsSelectable(false)
                 post { setTextIsSelectable(true) }
              }
              

              并像这样使用它

                  textView.text = "the content"
              
                  textView.fixTextSelection()
              

              【讨论】:

                猜你喜欢
                • 2016-07-07
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-09-04
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多