首页 > 解决方案 > RecyclerView 中的动态线性布局

问题描述

我有一个带有卡片的 RecyclerView,如下所示:

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cv"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="5dp"
    card_view:cardPreventCornerOverlap="false"
    card_view:cardCornerRadius="5dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="48dp">

            <TextView
                android:id="@+id/fragment_acts_list_item_header"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:background="@android:color/holo_red_dark"
                android:gravity="center_vertical"
                android:maxLines="1"
                android:padding="10dp"
                android:text="Header text"
                android:textColor="@android:color/white"
                android:textSize="20sp" />

            <!--My dropdown Button -->
            <RelativeLayout
                android:id="@+id/button"
                android:layout_width="48dp"
                android:layout_height="48dp"
                android:layout_alignParentEnd="true"
                android:layout_gravity="end"
                android:gravity="center">

                <View
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_alignParentEnd="false"
                    android:background="@drawable/ic_collapse_act" />

            </RelativeLayout>

        </RelativeLayout>

        <!-- Contains items that are visible without expanding -->
        <LinearLayout
            android:id="@+id/fragment_acts_list_visible_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            />

        <!-- Contains items that are visible after expanding -->
        <LinearLayout
            android:id="@+id/fragment_acts_list_expandable_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:orientation="horizontal" />

    </LinearLayout>

</android.support.v7.widget.CardView>

我从 API 获得了两张地图:首先包含要在屏幕上一直显示的元素(必须添加到上面代码中的fragment_acts_list_visible_layout),其他包含在用户单击展开按钮时必须显示的元素(上面代码中的按钮,必须添加到上面代码中的fragment_acts_list_expandable_layout中)。

我想用上面的布局表示两个地图的每个地图条目:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:weightSum="10">

    <TextView
        android:id="@+id/act_row_field_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:layout_weight="7"
        android:textAlignment="center" />

    <TextView
        android:id="@+id/act_row_field_value"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:layout_weight="3"
        android:textAlignment="center" />

</LinearLayout>

如何以正确的方式做到这一点?

使用诸如viewHolder.visibleLayout.addView(row);inonBindViewHolder方法之类的代码会给我重复的可见元素和错误的可扩展布局高度,因为这就是 RecyclerView 的onBindViewHolder工作方式(多次调用,每次调用都添加我的行)。

UPD:这是我的 bindViewHolder 方法:

@Override
public void onBindViewHolder(@NonNull final ExpandableRecyclerAdapter.ViewHolder viewHolder,
                             int i) {
    viewHolder.setIsRecyclable(false);
    Act act = acts.get(i);
    ActToDisplay visibleSettings = formatActFields(act, viewSettings);

    for (Map.Entry<String, String> entry : visibleSettings.getVisibleFields().entrySet()) {
        LinearLayout row = (LinearLayout) LayoutInflater.from(context)
                .inflate(R.layout.act_row, viewHolder.visibleLayout, false);
        TextView fieldName = row.findViewById(R.id.act_row_field_name);
        TextView fieldValue = row.findViewById(R.id.act_row_field_value);
        fieldName.setText(entry.getKey());
        fieldValue.setText(entry.getValue());
        viewHolder.visibleLayout.addView(row);
    }

    for (Map.Entry<String, String> entry : visibleSettings.getInvisibleFields()
            .entrySet()) {
        LinearLayout row = (LinearLayout) LayoutInflater.from(context)
                .inflate(R.layout.act_row, viewHolder.expandableLayout, false);
        TextView fieldName = row.findViewById(R.id.act_row_field_name);
        TextView fieldValue = row.findViewById(R.id.act_row_field_value);
        fieldName.setText(entry.getKey());
        fieldValue.setText(entry.getValue());
        viewHolder.expandableLayout.addView(row);
    }

    //check if view is expanded
    final boolean isExpanded = expandState.get(i);
    viewHolder.expandableLayout.setVisibility(isExpanded ? View.VISIBLE : View.GONE);

    viewHolder.buttonLayout.setRotation(expandState.get(i) ? 180f : 0f);
    viewHolder.buttonLayout.setOnClickListener(v -> onClickButton(viewHolder.expandableLayout, viewHolder.buttonLayout, i));
}

UPD2: 通过添加.removeAllViews() in both visible and invisible layouts inonViewRecycled` 方法解决,但第二个问题没有消失 - 可扩展布局高度太大。

这是来自模拟器的屏幕,在单击展开后必须显示 1 个可见元素和另外一个。为什么这张卡那么大(好像把 wrap_content 算错了)? 在此处输入图像描述

UPD3: 可扩展布局高度的问题是我的错误 - 我已将可扩展布局方向设置为水平而不是垂直

感谢@AbuYousuf 和@pskink

标签: androidandroid-recyclerview

解决方案


RecyclerView重用现有视图。当您滚动时,RecyclerView使用现有视图来显示其项目。所以清除之前添加的所有视图visibleLayout

  viewHolder.visibleLayout.removeAllViews();
   for (Map.Entry<String, String> entry : visibleSettings.getVisibleFields().entrySet()) {
    LinearLayout row = (LinearLayout) LayoutInflater.from(context)
            .inflate(R.layout.act_row, viewHolder.visibleLayout, false);
    TextView fieldName = row.findViewById(R.id.act_row_field_name);
    TextView fieldValue = row.findViewById(R.id.act_row_field_value);
    fieldName.setText(entry.getKey());
    fieldValue.setText(entry.getValue());
    viewHolder.visibleLayout.addView(row);
}

expandableLayout在添加之前删除视图。


推荐阅读