具有可变项目高度的水平RecyclerView无法正确包装 [英] Horizontal RecyclerView with variable item heights not wrapping properly

查看:122
本文介绍了具有可变项目高度的水平RecyclerView无法正确包装的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我打算实现的目标

项目视图应占据项目的整个高度

The item view should occupy the entire height of the item

该物品的高度可能小于recyclerview中最高的物品的高度,在这种情况下,它应该像上面的屏幕截图一样粘在顶部.

It could be that the item height is lesser than the height of the tallest item in the recyclerview, in which case it should just stick to the top like in the screenshot above.

我遇到的错误

如上面的屏幕截图所示,视图已被截断.

As in the screenshot above, views are getting truncated.

到目前为止我尝试过的事情

最初,我支持在recyclerview上使用wrap_content,因为它已经受支持了.当当时屏幕上看不到的视图最高时,这是行不通的.这在视图层次结构的布局方式上是有意义的. 如果高度与该数据相关,那么该高度甚至如何还没有被绑定到数据上,该如何计算呢?

Initially I went with wrap_content on the recyclerview, now that it is supported. It didn't work when none of the views visible on the screen at the time were the tallest. This makes sense in how the view hierarchy is laid out. How can the height of something which hasn't even been bound to any data yet be calculated if the height is dependent on that data?

解决时间:S

我没有尝试使用自定义布局管理器,而是首先进行了我认为需要做的事情-在开始时布置所有项目视图以弄清它们的高度.

Instead of trying a custom layoutmanager, I first went with what I felt needed to be done - laying out all item views at the beginning to figure out their height.

在屏幕上部播放进度条和动画,以引起用户的注意,而所有这些都发生在将recyclerview可见性设置为不可见的情况下.我用两件事,一个还不够-我在适配器的onViewAttached()调用中附加了一个观察者,并且我还使用了滚动更改侦听器.回收器视图上附加了LinearSnapHelper,可捕捉到滚动条上的相邻位置(下一个或上一个,取决于滚动方向).

There's a progressbar and an animation playing in the upper part of the screen to catch the user's attention while all this happens with recyclerview visibility set to invisible. I use two things, one didn't suffice - I've attached an observer in the adapter's onViewAttached() call and I've used a scroll change listener as well. There's a LinearSnapHelper attached to the recycler view to snap to adjacent (next or previous, depending on the scroll direction) position on scroll.

在此设置中,

  1. 我要使用layoutManager.smoothScrollToPosition()
  2. 进入recyclerview中的每个位置
  3. 使用以下子项获取子视图的高度

  1. I'm going to each position in the recyclerview using layoutManager.smoothScrollToPosition()
  2. Getting the child view height using

        View currentChildView = binding.nextRv.getChildAt(layoutManager.findFirstCompletelyVisibleItemPosition());
        if (currentChildView != null) {
            currentChildHeight = currentChildView.getHeight();
        }

RecyclerView.SCROLL_STATE_IDLE上的滚动更改侦听器中,或者通过将高度传递到适配器的onViewAttachedToWindow()中上面提到的视图附加观察器中

in scroll change listener on RecyclerView.SCROLL_STATE_IDLE or by passing the height to the view attached observer mentioned above in the adapter's onViewAttachedToWindow()

@Override
public void onViewAttachedToWindow(BindingViewHolder holder) {
    if (mObserver != null) {
        mObserver.onViewAttached(holder.binding.getRoot().getHeight());
    }
}

  1. 存储一个maxHeight,该值会更改为maxHeight的最大值和新孩子的身高.
  1. Storing a maxHeight that changes to the max of maxHeight and new child's height.

很明显,这很丑陋.另外,它不能提供当前视图的高度-onAttached表示仅是附加视图,没有测量和布置.它是回收的视图,而不是绑定到当前数据项的视图.这就带来了诸如上述的视图截断之类的问题.

As is evident, this is ugly. Plus it doesn't give me the current view's height - onAttached means it's only just attached, not measured and laid out. It is the recycled view, not the view bound to current data item. Which presents problems like the truncation of view illustrated above.

我还尝试了在回收者视图中wrap_content的高度,并使回收者的父级无效,直到回收者和滚动中的孩子到达SCROLL_STATE_IDLE为止.不起作用.

I've also tried wrap_content height on the recycler view and invalidating from recycler's parent till the recycler and the child on scroll coming to SCROLL_STATE_IDLE. Doesn't work.

我不确定自定义布局管理器如何在这里提供帮助.

I'm not sure how a custom layoutmanager can help here.

有人可以指引我正确的方向吗?

Can someone guide me in the right direction?

推荐答案

我无法接受@Pradeep Kumar Kushwaha的回答,因为针对一种解决方案,我不希望列表中使用不同的字体大小.一致性是设计中的关键要素.他给出的第二种选择无法使用,因为使用ellipsize,我需要给用户提供某种更多"按钮,以便用户阅读全部内容,并且我的文本视图已经采取了单击操作.将 more 放置在其他位置也不是一个好的设计.

I could not accept @Pradeep Kumar Kushwaha's answer because against one solution, I do not want different font sizes in the list. Consistency is a key element in design. Second alternative he gave couldn't work because with ellipsize I would need to give a "more" button of some sort for user to read the entire content and my text view is already taking a click action. Putting more some place else would again not be good design.

以最高的截断项目成为焦点时改变大小recyclerview的简单折衷来更改设计,这变成了notifyItemChanged()的简单用例.即使是我尝试使用附有视图的观察器和滚动状态侦听器进行的尝试,也可以使用notifyItemChanged,但是这种方法太过分了.我可以在代码和设计中同时使用.这是所需的代码.

Changing the design with the simple compromise of resizing the recyclerview when the tallest, truncated item comes into focus, it turns into the simple use case of notifyItemChanged(). Even for the attempt I made using the view attached observer and scroll state listener, notifyItemChanged could be used but that approach is just too hacky. This I can live with in both code and design. Here goes the code required.

@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
        int position = ((LinearLayoutManager) binding.nextRv.getLayoutManager())
                .findFirstVisibleItemPosition();
        if (position != nextSnippetAdapter.getItemCount() - 1) {
            binding.nextRv.getAdapter().notifyItemRangeChanged(position, 2);
        } else {
            binding.nextRv.getAdapter().notifyItemChanged(position);
        }
    }
}

对于我的特定设置,只需调用这两个元素即可.可以对其进行进一步优化,以便在大多数情况下在position + 1处调用单个元素,并在角落(实际)情况下检查并调用适当的元素.

For my particular setup, calling for just these two elements works. It can further be optimized so as to call for single element at position + 1 in most cases, and checking and calling for the appropriate one in corner (literal) cases.

这篇关于具有可变项目高度的水平RecyclerView无法正确包装的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆