“android:textIsSelectable =”true“不适用于RecyclerView中的TextView

时间:2016-04-22 19:02:28

标签: android android-recyclerview textview

我知道在{x}中为android:textIsSelectable="true"设置TextView将显示本机文本选择弹出窗口,我一直在我的应用程序中使用它。但是当我尝试在附加到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宽度从wrap_content更改为match_parent

我知道我可以这样做,但我的问题是如何解决这个问题,因为它对我来说很奇怪。而且,如果我想将宽度保持为match_parent,那么解决方案是什么。

欢迎任何意见。

9 个答案:

答案 0 :(得分:3)

如果您在android:descendantFocusability="blocksDescendants"​recyclerview中添加listview,请将其删除。 检查完毕后

答案 1 :(得分:3)

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

android:descendantFocusability="beforeDescendants"

然后在rowitem布局的TextView中添加

android:textIsSelectable="true"

答案 2 :(得分:1)

似乎有很多人对此有疑问,并且有迹象表明它可能是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>

答案 3 :(得分:1)

Add In Your RecyclerView Adapter:

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

its worked for me..

答案 4 :(得分:1)

override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
    yourTextView.fixTextSelection()
}

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

答案 5 :(得分:0)

我发现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());
}

您可以在仿真器中调试并跟踪此代码。

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

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

}

答案 8 :(得分:0)

最终和可行的解决方案

在你的 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()