在RecyclerView中创建最后一个项目/ ViewHolder,填充屏幕的其余部分或具有最小高度

问题描述 投票:14回答:2

我正在努力使用RecyclerView。我使用recyclerview来显示我的模型类的详细信息。

//My model class
MyModel {
    String name;
    Double latitude;
    Double longitude;
    Boolean isOnline;
    ...
}

由于某些值可能不存在,我使用RecyclerView和自定义视图类型(一个代表我的模型的每个值)。

//Inside my custom adapter
public void setModel(T model) {
    //Reset values
    itemCount = 0;
    deviceOfflineViewPosition = -1;
    mapViewPosition = -1;

    //If device is offline, add device offline item
    if (device.isOnline() == null || !device.isOnline()) {
        deviceOfflineViewPosition = itemCount;
        itemCount++;
    }

    //Add additional items if necessary
    ...

    //Always add the map as the last item
    mapViewPosition = itemCount;
    itemCount++;

    notifyDataSetChanged();
}

@Override
public int getItemViewType(int position) {
    if (position == deviceOfflineViewPosition) {
        return ITEM_VIEW_TYPE_OFFLINE;
    } else if (position == mapViewPosition) {
        return ITEM_VIEW_TYPE_MAP;
    } else if (...) {
        //Check for other view types
    }
}

使用RecyclerView,我可以在运行时轻松确定哪些值可用,并将相应的项添加到RecyclerView数据源。我简化了代码,但我的模型有更多的值,我有更多的视图类型。

RecyclerView中的最后一项始终是地图,并且始终存在。即使我的模型中根本没有任何价值,也至少会有一个项目,即地图。

问题:如何让RecyclerView中的最后一项填充屏幕上的剩余空间并且还有最小高度。尺寸应该是更大的价值:剩余空间或最小高度。例如:

  • 模型有几个值,总计占用600dp屏幕的100dp - >地图高度应为500dp
  • 模型有很多值,总计占用600dp的600dp屏幕 - >地图高度应该是最小值200dp
  • 模型没有值 - >地图填充整个屏幕

enter image description here

android google-maps android-recyclerview adapter android-adapter
2个回答
5
投票

在布置最后一项后,您可以在RecyclerView中找到剩余空间,并将剩余空间添加到最后一项的minHeight中。

val isLastItem = getItemCount() - 1 == position
if (isLastItem) {
            val lastItemView = holder.itemView
            lastItemView.doOnLayout {
                val recyclerViewHeight = recyclerView.height
                val lastItemBottom = lastItemView.bottom
                val heightDifference = recyclerViewHeight - lastItemBottom
                if (heightDifference > 0) {
                    lastItemView.minimumHeight = lastItemView.height + heightDifference
                }
            }
        }

onBindHolder中,使用getItemCount() - 1 == position检查项目是否为最后一项。如果它是最后一项,则通过使用lastItem底部减去recyclelerView高度来找到高度差(getBottom()为您提供相对于其父级的视图的最底部像素。在这种情况下,我们的父级是RecyclerView)。

如果差值大于0,则将其添加到上一个视图的当前高度并将其设置为minHeight。我们将其设置为minHeight而不是直接设置为height以支持最后一个视图的动态内容更改。

注意:此代码为Kotlin,doOnLayout函数来自Android KTx。你的RecyclerView高度应该是match_parent这个工作(我想这是显而易见的)。


0
投票

我使用muthuraj解决方案来解决类似的问题,如果以前的项目填满页面的高度或更高的高度,我希望最后一项显示在最后一项,但如果前一项没有填满高度,我希望最后一项显示在页面底部。

当前一项+ specialItem占据所有位置。 -------------- 项目 项目 项目 specialItem --------------

当前一项+ specialItem超过高度时 -------------- 项目 项目 项目 项目 项目 项目 specialItem --------------

当前一项+ specialItem小于高度时 -------------- specialItem -------------- 要么 -------------- 项目 specialItem --------------

存档这个我使用这个代码

val lastItemView = holder.itemView
            //TODO use a better option instead of waiting for 200ms
            Handler().postDelayed({
                val lastItemTop = lastItemView.top
                val remainingSpace = recyclerViewHeight() - lastItemTop
                val heightToSet = Math.max(remainingSpace, minHeight)

                if (lastItemView.height != heightToSet) {
                    val layoutParams = lastItemView.layoutParams
                    layoutParams.height = heightToSet
                    lastItemView.layoutParams = layoutParams
                }
            }, 200)

我使用Handler()。postDelayed的原因是doOnLayout永远不会被我调用,我无法弄清楚为什么这样,而是以200ms的延迟运行代码,直到找到更好的工作方式。

© www.soinside.com 2019 - 2024. All rights reserved.