I'm struggeling with the RecyclerView. I use a recycler view to display the details of my model class.
//My model class
MyModel {
String name;
Double latitude;
Double longitude;
Boolean isOnline;
...
}
Since some of the values might not be present, I use the RecyclerView with custom view types (one representing each value of my model).
//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
}
}
With the RecyclerView I can easily determine at runtime which values are available and add corresponding items to the RecyclerView datasource. I simplyfied the code but my model has a lot more values and I have a lot more view types.
The last item in the RecyclerView is always a map and it is always present. Even if there is no value at all in my model, there will at least be one item, the map.
PROBLEM: How can I make the last item in RecyclerView fill the remaining space on screen and also have a min heigh. The size shall be what ever value is lager: the remaining space or the min height. For example:
- Model has a few values, which in sum take up 100dp of a 600dp screen -> map heigh should be 500dp
- Model has a lot of values, which in sum take up 500dp of a 600dp screen -> map heigh should be a min value of 200dp
- Model has no values -> map fills whole screen
You can find the remaining space in RecyclerView after laying out the last item and add that remaining space to the minHeight
of the last item.
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
}
}
}
In onBindHolder
check if the item is last item using getItemCount() - 1 == position
. If it is the last item, find the height difference by subtracting recyclerView height with lastItem bottom (getBottom()
gives you the bottom most pixel of the view relative to it's parent. In this case, our parent is RecyclerView
).
If the difference is greater than 0, then add that to the current height of the last view and set it as minHeight
. We are setting this as minHeight
instead of setting directly as height
to support dynamic content change for the last view.
Note: This code is Kotlin, and doOnLayout function is from Android KTx. Also your RecyclerView
height should be match_parent
for this to work (I guess that's obvious).
I used muthuraj solution to solve a similar problem, I wanted the last item to be shown at the last normally if previous items fill up the height of the page or more height but in case the previous item doesn't fill up the height, I wanted last item to be shown on the bottom of the page.
When previous item + specialItem take all the place.
--------------
item
item
item
specialItem
--------------
When previous item + specialItem take more than the height
--------------
item
item
item
item
item
item
specialItem
--------------
When previous item + specialItem take less than the height
--------------
specialItem
--------------
or
--------------
item
specialItem
--------------
to archive this I use this code
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)
the reason I use Handler().postDelayed is that doOnLayout never gets called for me and I couldn't figure out why so instead run the code with 200ms delay until I found something better to work with.
来源:https://stackoverflow.com/questions/41253811/make-last-item-viewholder-in-recyclerview-fill-rest-of-the-screen-or-have-a-mi