android recyclerview - TextView 无法使用 setmaxlines 方法正确扩展

android recyclerview - TextView is not expanding properly with setmaxlines method

我是 android 开发的新手。出于我的学习目的,我正在开发一个 android 应用程序来在回收器视图中列出斐波那契数列。当用户向下滚动回收器视图时,列表会附加新的数字。

该图显示了在回收站视图中显示索引和索引的相应斐波那契数的应用程序

这是回收站视图中单个项目的布局xml。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:clickable="false"
    android:focusable="false"
    android:padding="5dp">

    <TextView
        android:id="@+id/info_index"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="3"
        android:background="#CDD6D5"
        android:gravity="center"
        android:maxLines="1" />

    <TextView
        android:id="@+id/info_value"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="#CDD6D5"
        android:gravity="center"
        android:maxLines="1" />

</LinearLayout>

适配器节选 class,

public class ViewHolder extends RecyclerView.ViewHolder {
        final TextView index;
        final TextView value;

        ViewHolder(View itemView) {
            super(itemView);
            index = itemView.findViewById(R.id.info_index);
            value = itemView.findViewById(R.id.info_value);
        }
    }

    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        final TextView value = holder.value;
        final TextView index = holder.index;
        value.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.KITKAT)
            @Override
            public void onClick(View v) {
                if (value.getMaxLines() == 1000) {
                    value.setMaxLines(1);
                    notifyItemChanged(position);
                } else {
                    value.setMaxLines(1000);
                    notifyItemChanged(position);
                }
            }
        });
        Log.d(TAG, "position-value:" + String.valueOf(position));

        holder.index.setBackgroundColor(Color.WHITE);
        holder.index.setText(String.valueOf(position + 1));
        holder.value.setBackgroundColor(Color.WHITE);
        holder.value.setText(mData.get(position));

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            holder.index.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
            holder.value.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
        }

    }

当我点击值 textview 时,textview 在第一次点击时没有展开,而是我必须按两次才能展开。第一次只有闪烁发生。我试过禁用 recyclerview 的动画师,尝试在回收站视图中重新使用相同的视图,但没有任何帮助。

我的要求是在点击时展开斐波那契值文本视图。默认情况下,它应该是 1 行,当点击它时,它应该显示多行的全部内容(尽可能多)。

目前,点击两次即可发生这种情况。第一次闪烁,第二次扩大。

我认为这是 android 代码中的错误。但只想在这里确认我可能错过的任何解决方案。

我能够在我的设备上重复你的问题,你遇到的问题是你的 LinearLayout 在到达你的 textview 之前消耗了你的点击。

包括:

android:clickable="false"
android:focusableInTouchMode="false"
android:focusable="false"

像这样在你的 LinearLayout 中:

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:clickable="false"
    android:focusableInTouchMode="false"
    android:focusable="false"
    android:padding="5dp">

    <TextView
        android:id="@+id/info_index"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="3"
        android:background="#CDD6D5"
        android:gravity="center"
        android:maxLines="1" />

    <TextView
        android:id="@+id/info_value"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="#CDD6D5"
        android:gravity="center"
        android:maxLines="1" />

</LinearLayout>

还包括:

android:nestedScrollingEnabled="false"

在你的 RecyclerView 中

闪烁的原因是,每次单击项目时,在设置 maxLines 之后,您正在调用 notifyItemChanged(这是正确的做法),但结果是,在重绘项目之前 onBindViewHolder 是又叫了。因此,当它再次被调用时,应该有一种方法可以知道该项目的当前最大行数。

此外,如果您尝试添加大量项目并上下滚动,您会看到更多错误(因为重用了查看器)因此,set/reset onBindViewHolder 中每个项目的最大行数很重要(但外部点击侦听器)

其次,RecyclerView 的 DefaultItemAnimator 在项目更改时使用交叉淡入淡出动画,默认情况下,它会为该位置创建两个视图持有者,以便在两者之间交叉淡入淡出。因此,在上面,您在“值”textview 上设置了一个 clicklistener,并在 onClick 回调中干扰了 textview。但是,当您稍后单击并通知适配器该项目已更改时,它会绑定第二个 viewholder 实例。因此,当您单击时,您的单击会被先前的“值”实例消耗掉,紧接着会绑定一个新实例,并且您会为第二个 viewholder 实例设置一个新的 clicklistener。

这是干扰点击侦听器内的查看器项目容易出​​错的众多原因之一。有时人们用 setTag/getTag 解决这类问题,但我认为它也同样容易出错。

我认为最简单的解决方案是为每个项目使用 POJO(普通旧 java 对象)并在此 POJO 中包含 maxLine 状态。类似 FibonacciItem 的字段,例如 int: index, String: fibonacciNumber, boolean : expanded。然后您将提供该列表作为 FibonacciItems 列表。在您的点击侦听器中,您将更新被点击项目的最大行数。像这样:

public void onClick(View v) {
      if (mList.get(position).isExpanded()) {
          mList.get(position).setExpanded(false);
          notifyItemChanged(position);
      } else {
          mList.get(position).setExpanded(true);
          notifyItemChanged(position);
      }

}

在你的 onBindViewHolder 中,(但在你的点击侦听器之外)你应该根据这个值为每个项目设置最大行数:

if(mList.get(position).isExpanded(){
    holder.value.setMaxLines(1);
 } else {
    holder.value.setMaxLines(1000);
 }

这将解决问题。此外,我们通常对列表中的每个项目使用 POJO(或数据 类)。更容易管理。