I'm working on a Firemonkey TListView
to display search results. This list loads 25 items at a time, but could potentially show hundreds of items.
I need to detect when the user has scrolled down to the bottom, so that I can fetch the next 25 items to show in the list. However, I cannot find the appropriate properties to determine this.
There's the OnPullRefresh
event, but that applies to scrolling to the top of the list and pulling it down. What I need is similar, but for the bottom of the list instead of the top.
There's the OnScrollViewChange
event, which seems appropriate. There's also the ScrollViewPos
property, which is also useful. However, I cannot figure out what to compare that number to - specifically, the maximum possible value for ScrollViewPos
. Something like ScrollViewMax
is what I would need.
But I cannot find anything more to accurately detect that user has scrolled to the bottom.
How can I detect when a user has scrolled to the bottom of a Firemonkey TListView
so that I can load more search results?
EDIT
If this is not possible for whatever reason, there is an alternative to add a dummy item to the end of the list with a "Load More..." button. But I'd rather it be automated.
EDIT2
I forgot to mention... I have the Search Box showing in this list view, and items can have a variable height. If calculating this based on item contents is the only way, then such a calculation needs to be perfect. I don't want to know when user is "approaching" or "near" the bottom, but when user exactly hits the bottom of the list.
Further investigation I found the following in
function TListViewBase.GetItemRect(const AItemIndex: Integer): TRectF;
If you go deeper in
function TListViewBase.GetItemRelRect(const Index: Integer; const LocRect: TRectF;
const SideSpace: Integer = 0): TRectF;
then you will realize that the last item's Top is
listview1.GetItemRect(listview1.ItemCount-1).top+listview1.ScrollViewPos-listview1.SideSpace-listview1.LocalRect.top
whatever was your items variable height. This represents the value of FHeightSums[Index]
which is a list containing the sum of height till the item with Index Index
Now to the problem: You want the calculation to be perfect. you want a touch down.
And this is it
procedure TForm5.ListView1ScrollViewChange(Sender: TObject);
var
Tmp_top : single;
begin
Tmp_top := listview1.GetItemRect(listview1.ItemCount-1).top+listview1.ScrollViewPos-listview1.SideSpace-listview1.LocalRect.top;
if Tmp_top+listview1.GetItemRect(listview1.ItemCount-1).height-listview1.Height=listview1.ScrollViewPos-2*listview1.SideSpace then
showmessage('touch down');
end;
Edit: if you further simplify this formula you will end up in the other answer with few upgrades
procedure TForm5.ListView1ScrollViewChange(Sender: TObject);
begin
if listview1.GetItemRect(listview1.ItemCount-1).bottom=listview1.Height-listview1.SideSpace then
showmessage('touch down');
end;
now this will cover any changes in padding, margins, sidespace, searchbox visibility and searchbox size changing.
Try this code. Self-explanatory I think...
procedure TForm1.ListView1ScrollViewChange(Sender: TObject);
var
R: TRectF;
begin
if TListView(Sender).ItemCount > 0 then // Just in case...
begin
// Get the last item's Rect
R := TListView(Sender).GetItemRect(TListView(Sender).ItemCount - 1);
// Bottom?
if R.Bottom = TListView(Sender).Height then
Caption := 'Reached bottom!'
else
Caption := 'Bottom not reached yet.';
end;
end;