优化显示在 RecyclerView 中的项目的复杂布局

Optimise a complex layout for an item displayed inside a RecyclerView

我必须在 RecyclerView 中显示来自 json feed 的帖子,并且我有一个布局,用于显示单行在 RecyclerView 中的外观,如下所示

我还没有在我的实际布局中实现底部部分,它包含上图中的红色和绿色框,我的布局看起来像这样

我还实现了滑动删除和撤消,如您所知,它需要一个 FrameLayout 作为根,它下面有 2 个节点,一个显示正常区域,一个显示滑动时显示的布局。在我的例子中,当我滑动项目时,这就是你将看到的。

现在的问题是,每行有 13 个视图,我不喜欢这种可能性,我将在给定时间在 RecyclerView 中显示最多 100 个项目,如您所见,这将导致到大量的浏览量。 我有一些想法来制作自定义视图以减少行中的视图数量。根据您的意见,优化此视图的最佳方法是什么,或者我应该说,减少 RecyclerView 中每行的视图数。我从 JSON 获取所有数据,并且中央文本区域本质上需要根据其状态进行“阅读更多”或“阅读更少”的扩展。

方法一

稍微简化

在这个方法中,我将左上角的人的个人资料图片,带有姓名和更新时间的TextView组合成一个自定义View,换句话说,它将从View扩展,有自己的canvas 用于绘制位图、字符串,但我必须在 Android 中使用 StaticLayout 手动编码 RTL 和 LTR 以及其他项目。我需要中央文本区域在本质上是可扩展的,所以我会坚持使用每个人在 Whosebug 上不断提到的可扩展视图之一。

方法二

高度模块化的自定义 UI 组件。

整个图表由用户的图像、带有名称的文本、时间、中心文本和图像组成,可以做成一个 CustomView,我不确定如何使它可扩展,因为 StaticLayout 一旦在 Android无法修改。你怎么认为?这是正确的方法吗?如果我把整个东西做成一个视图,我最终每行只有 4 children。这是自定义视图的有效用例吗?

嗯,我自己找到了答案。我正在处理两种类型的 post 项目,一种包含 ImageView 以显示 16:9 post 图像,另一种不包含。到目前为止,我的 RecyclerView 在滚动操作中严重滞后,因为我只有一个布局文件,其中的 ImageView 的宽度设置为 match_parent,高度设置为 wrap_content。当我滚动时,带有图像的 posts 使用 Glide 加载图像并调用 requestLayout() 因为这些项目的大小正在改变。这导致过多的 requestLayout() 调用导致滚动时严重滞后。

我是如何解决这个问题的?

我制作了一个适配器,它被分为两种类型的行。

@Override
public int getItemViewType(int position) {
    if (mResults != null) {
        return mResults.get(position).getPicture() != null ? IMAGE : NO_IMAGE;
    }
    return NO_IMAGE;
}

根据当前位置的结果是否包含 post 中的图像,我修改了我的 onCreateViewHolder 方法以设置 ImageView 的预定义大小,以防我的项目有 post 图片。

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view;
    if (viewType == IMAGE) {
        view = mLayoutInflater.inflate(R.layout.row_post_image, parent, false);
        RowImageHolder holder = new RowImageHolder(view);

        //To set the width and height of the ImageView of our image in the post, we get its LayoutParams and adjust its width and height to maintain 16:9 ratio
        ViewGroup.LayoutParams params = holder.mPostPicture.getLayoutParams();
        params.width = mPostImageWidth;
        params.height = mPostImageHeight;
        holder.mPostPicture.setLayoutParams(params);
        return holder;
    } else {
        view = mLayoutInflater.inflate(R.layout.row_post_image, parent, false);
        RowNoImageHolder holder = new RowNoImageHolder(view);
        return holder;
    }
}

这就是所有需要做的事情。如果项目的类型支持图像,则 onBindViewHolder 会设置图像。好处是 space 为那些有图像的项目提前保留,滚动时 RecyclerView 的性能大大提高。到目前为止,我在没有使用任何自定义视图的情况下实现了这一点:)