How to detect when FMX List View is scrolled to th

2019-08-05 08:02发布

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.

2条回答
疯言疯语
2楼-- · 2019-08-05 08:22

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.

查看更多
冷血范
3楼-- · 2019-08-05 08:23

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;
查看更多
登录 后发表回答