The current code tests bottom against ScrollPosition + Height with bottom starting from 0:
B4X:
'Gets the index of the last visible item.
Public Sub getLastVisibleIndex As Int
Dim first As Int = getFirstVisibleIndex
Dim bottom As Int
For i = first To items.Size - 1
bottom = bottom + heights.Get(i) + dividerHeight
If bottom >= sv.ScrollPosition + sv.Height Then Return Max(i - 1, first)
Next
Return items.Size - 1
End Sub
It seems that the test, if i starts at FirstVisibleIndex, should be against the height of the visible items, as follows:
B4X:
'Gets the index of the last visible item.
Public Sub getLastVisibleIndex As Int
Dim first As Int = getFirstVisibleIndex
Dim bottom As Int
For i = first To items.Size - 1
bottom = bottom + heights.Get(i) + dividerHeight
If bottom >= sv.Height Then Return Max(i - 1, first)
Next
Return items.Size - 1
End Sub
Attached. In the top CustomListView on my device I see items 26-30 (and the divider between 25 and 26). In the log I see First=25, Last=49. Which raises the question, should FirstVisibleItem be returning the actual first visible item, rather than the divider between items?
Public Sub getLastVisibleIndex As Int
Dim first As Int = getFirstVisibleIndex
Dim bottom As Int
For i = 0 To items.Size - 1
bottom = bottom + heights.Get(i) + dividerHeight
If i >= first And bottom >= sv.ScrollPosition + sv.Height Then Return Max(i - 1, first)
Next
Return items.Size - 1
End Sub