具有动态高度项的水平RecyclerView

44

我需要一个横向的RecyclerView,但它们内部的项目高度是根据从后端返回的内容动态确定的。

RecyclerView和其中的项目高度为“wrap_content”。

问题在于,如果RecyclerView中可见的第一个项目很小,那么当用户滚动到较大的项目时,它们会出现被截断的情况。

理想情况下,我们希望RecyclerView足够大,以容纳组中最大的项目(但仅限于实际存在的最大项目...而不是假设的最大项目)。 RecyclerView 动态更改其高度也是可以接受的。

我编写了一个示例应用程序来说明这个问题。 在此应用程序中,我们有一个水平列表。 前33个项目应显示1行文本,而下一个应显示3行文本,最后34个应显示2行文本。 但是,它们都显示为1行,因为RecyclerView的高度不会改变。

我已经尝试从onBindViewHolder()调用requestLayout()在RecyclerView(和TextView)上,但似乎没有任何作用。

MainActivity

public class MainActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAdapter = createAdapter();

        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
        mRecyclerView.setAdapter(mAdapter);
    }

    private RecyclerView.Adapter<ViewHolder> createAdapter() {
        RecyclerView.Adapter adapter = new RecyclerView.Adapter<ViewHolder>() {
            @Override
            public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
                return new ViewHolder(v);
            }

            @Override
            public void onBindViewHolder(ViewHolder holder, int position) {
                if (position < 33) {
                    holder.mText.setText("1 line");
                } else if (position > 66) {
                    holder.mText.setText("2 lines\n2 lines");
                } else {
                    holder.mText.setText("3 lines\n3 lines\n3 lines");
                }
            }

            @Override
            public int getItemCount() {
                return 100;
            }
        };
        return adapter;
    }

    private static class ViewHolder extends RecyclerView.ViewHolder {
        TextView mText;
        public ViewHolder(View itemView) {
            super(itemView);
            mText = (TextView) itemView.findViewById(R.id.text);
        }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#888888">
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hi"
        android:textSize="30sp" />

</LinearLayout>

使用最新的25.1.1版本。 - Gak2
1
@Gak2,我想知道你是否已经找到了解决方案,因为我现在也面临着同样的问题。 - Miriana Itani
1
Gak2和@MirianaItani:这个对我有用。 - Alix
有相同的问题,请在找到解决方案后通知我吗? - Shashwat Gupta
@Gak2,你找到解决方案了吗? - saintjab
显示剩余7条评论
7个回答

1

使用以下代码更改您的 item.xml 布局内容。 它将解决您的问题。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="160dp"
    android:layout_height="match_parent"
    android:background="#888888">
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hi"
        android:textSize="30sp" />

</LinearLayout>

0

您可以使用FlexboxLayoutManager Google库解决此问题,方法是将FlexDirection定义为FlexDirection.ROW,将FlexWrap定义为FlexWrap.NOWRAP,并在BaseViewHolder构造函数中为每个项目设置FlexShrink为0.0f,以便能够水平滚动。有关如何实现此操作的更多详细信息,请单击此处:具有动态项高度的水平RecyclerView


0

要让RecyclerView水平显示,您需要使用android:layout_centerHorizontal="true"。此外,其他的和垂直显示时一样。

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/RecyclerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/toolbar"/>

0

主活动:

public class MainActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAdapter = createAdapter();

        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
        mRecyclerView.setAdapter(mAdapter);
    }

    private RecyclerView.Adapter<ViewHolder> createAdapter() {
        RecyclerView.Adapter adapter = new RecyclerView.Adapter<ViewHolder>() {
            @Override
            public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
                return new ViewHolder(v);
            }

            @Override
            public void onBindViewHolder(ViewHolder holder, int position) {
                if (position < 33) {
                    holder.mText.setText("1 line");
                } else if (position > 66) {
                    holder.mText.setText("2 lines\n2 lines");
                } else {
                    holder.mText.setText("3 lines\n3 lines\n3 lines");
                }
            }

            @Override
            public int getItemCount() {
                return 100;
            }
        };
        return adapter;
    }

    private static class ViewHolder extends RecyclerView.ViewHolder {
        TextView mText;
        public ViewHolder(View itemView) {
            super(itemView);
            mText = (TextView) itemView.findViewById(R.id.text);
        }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>

item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#888888">
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hi"
        android:textSize="30sp" />

</LinearLayout>

0

将您的recyclerView高度和宽度从wrap_content更改为match_parent,或者您也可以为您的recyclerView指定固定高度,例如android:layout_height="150dp"

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#888888" />

</RelativeLayout>

或者你可以尝试

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:background="#888888" />

</RelativeLayout>

-1
尝试在您的textView中添加android:singleLine="false",当有多行时它会发生变化。

-7

只需要调用 itemAdapter.notifyDataSetChanged(); 就可以了。


请您将代码格式化,方法是将其高亮显示,然后按Ctrl+K。 - WhatsThePoint

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接