我正在使用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中的最后一项填满屏幕上的剩余空间,并且还有最小高度。尺寸应该是更大的价值:剩余空间或最小高度。例如:
答案 0 :(得分:4)
布局完最后一项后,您可以在RecyclerView中找到剩余空间,并将剩余空间添加到最后一项的TransactionSynchronizationManager.getResource(key)
中。
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
检查该项是否为最后一项。如果是最后一项,则通过在lastItem bottom减去recyclerView height来找到高度差(getItemCount() - 1 == position
给出了视图相对于其父视图的最底像素。在这种情况下,我们的父视图是getBottom()
)。
如果差异大于0,则将其添加到最后一个视图的当前高度并将其设置为RecyclerView
。我们将其设置为minHeight
,而不是直接设置为minHeight
,以支持最后一个视图的动态内容更改。
注意:此代码为Kotlin,而doOnLayout函数来自Android KTx。同样,您的height
高度应为RecyclerView
,这样才能正常工作(我想这很明显)。
答案 1 :(得分: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的延迟运行代码,直到找到更好的方法为止。
答案 2 :(得分:0)
您可以扩展LinearLayoutManager
来自己布置最后一个项目。
这是一个FooterLinearLayoutManager
,它将把列表的最后一项移到屏幕底部(如果尚不存在)。通过覆盖layoutDecoratedWithMargins
,LinearLayouyManager
调用了项目应该到达的位置,但我们可以将其与父级高度匹配。
注意::这不会“调整”视图的大小,因此精美的背景或类似内容可能无法工作,它只会将最后一项移至屏幕底部。
/**
* Moves the last list item to the bottom of the screen.
*/
class FooterLinearLayoutManager(context: Context) : LinearLayoutManager(context) {
override fun layoutDecoratedWithMargins(child: View, left: Int, top: Int, right: Int, bottom: Int) {
val lp = child.layoutParams as RecyclerView.LayoutParams
if (lp.viewAdapterPosition < itemCount - 1)
return super.layoutDecoratedWithMargins(child, left, top, right, bottom)
val parentBottom = height - paddingBottom
return if (bottom < parentBottom) {
val offset = parentBottom - bottom
super.layoutDecoratedWithMargins(child, left, top + offset, right, bottom + offset)
} else {
super.layoutDecoratedWithMargins(child, left, top, right, bottom)
}
}
}
答案 3 :(得分:0)
这对我有用,让recycler用layout_height =“ 0dp”视图,并将顶部约束放在相应的上面项的底部,并将底部约束放在父项,然后将其与剩余空间一起调整大小:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ToggleButton
android:id="@+id/toggleUpcomingButton"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:gravity="top"
android:text="@string/upcoming"
app:layout_constraintEnd_toStartOf="@+id/togglePupularButton"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ToggleButton
android:id="@+id/togglePupularButton"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top"
android:text="@string/popular"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/toggleUpcomingButton"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/popular_movies"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toggleUpcomingButton" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_title" />
</androidx.constraintlayout.widget.ConstraintLayout>