Delphi FMX TListView ScrollTo失效:动态高度Item无法准确定位
TListView动态高度Item的ScrollTo定位问题解决
将TListView的Item设置为DynamicAppearance后,通过OnUpdateObject事件动态计算每个Item的高度,视觉显示正常,但原生ScrollTo功能无法准确定位目标Item。尝试自定义ListViewScrollTo方法计算滚动位置时,多数情况下ListView.Items[i].Height返回0,导致无法得到正确的滚动高度。
自定义滚动方法
procedure ListViewScrollTo(const aListView: TListview); var i, lHeight: Integer; begin aListView.Repaint; lHeight := 0; for i := 0 to aListView.Items.Count - 1 do begin if i = aListView.ItemIndex then break; lHeight := lHeight + aListView.Items[i].Height + Round(aListView.ItemSpaces.top + aListView.ItemSpaces.Bottom); end; aListView.ScrollViewPos := lHeight; end;
OnUpdateObject事件中的自动计算Item高度代码
function GetTextHeight(const D: TListItemText; const Width: single; const Text: string): integer; var Layout: TTextLayout; begin Layout := TTextLayoutManager.DefaultTextLayout.Create; try Layout.BeginUpdate; try Layout.Font.Assign(D.Font); Layout.VerticalAlign := D.TextVertAlign; Layout.HorizontalAlign := D.TextAlign; Layout.WordWrap := D.WordWrap; Layout.Trimming := D.Trimming; Layout.MaxSize := TPointF.Create(Width, TTextLayout.MaxLayoutSize.Y); Layout.Text := Text; finally Layout.EndUpdate; end; //Size needs to be adjusted for Scale of Pixel density... Result := Round(Layout.Height * GetScreenScale); finally Layout.Free; end; end; function ListViewAutoSize(const Sender: TObject; const AItem: TListViewItem; aCustomItemTextName: string): Integer; var Drawable: TListItemText; Text: string; AvailableWidth: Single; Names: TStringList; SumHeight: Single; begin TListView(Sender).BeginUpdate; SumHeight := 0; Names := TStringList.Create; try Names.Delimiter := ';'; Names.StrictDelimiter := True; Names.DelimitedText := aCustomItemTextName; //do this for all items in aCustomItemTextName for var I := 0 to Names.Count - 1 do begin AvailableWidth := TListView(Sender).Width - TListView(Sender).ItemSpaces.Left - TListView(Sender).ItemSpaces.Right; Drawable := TListItemText(AItem.View.FindDrawable(Names[i])); //find item by name if assigned(Drawable) then begin //found if Drawable.Visible then begin Text := Trim(Drawable.Text); if Text <> '' then begin SumHeight := SumHeight; Drawable.PlaceOffset.Y := SumHeight ; Drawable.Height := GetTextHeight(Drawable, AvailableWidth, Text) * GetScreenScale; SumHeight := SumHeight + Drawable.Height; AItem.Height := Round(SumHeight); Drawable.Width := AvailableWidth; end else begin Drawable.Height := 0; end; end; end; end; //set Item size that everything is visible... AItem.Height := Round(SumHeight); Result := AItem.Height; finally Names.Free; end; TListView(Sender).EndUpdate; end;
问题根源与解决方法
问题根源
ListView.Items[i].Height返回0,核心原因是未进入可视区域的Item不会触发OnUpdateObject事件,导致高度未被计算,始终保持初始值0。
解决方法
1. 预计算并缓存所有Item高度
在ListView加载完数据后,主动触发所有Item的高度计算,将结果缓存到数组或Item的Tag属性中,避免依赖OnUpdateObject的延迟计算。
示例代码:
var ItemHeights: array of Integer; // 预计算所有Item高度 procedure PreCalculateItemHeights(const aListView: TListView; const CustomTextNames: string); var i: Integer; begin SetLength(ItemHeights, aListView.Items.Count); for i := 0 to aListView.Items.Count - 1 do begin // 调用现有高度计算方法 ItemHeights[i] := ListViewAutoSize(aListView, aListView.Items[i], CustomTextNames); // 同时将高度存入Item.Tag,作为备选缓存方式 aListView.Items[i].Tag := ItemHeights[i]; end; end;
2. 修改自定义滚动方法,使用缓存高度
不再直接读取Items[i].Height,改用预缓存的高度数据:
procedure ListViewScrollTo(const aListView: TListview); var i, lHeight: Integer; begin lHeight := 0; for i := 0 to aListView.ItemIndex - 1 do begin // 使用数组缓存的高度 lHeight := lHeight + ItemHeights[i] + Round(aListView.ItemSpaces.Top + aListView.ItemSpaces.Bottom); // 若用Tag缓存则替换为: // lHeight := lHeight + aListView.Items[i].Tag + Round(aListView.ItemSpaces.Top + aListView.ItemSpaces.Bottom); end; aListView.ScrollViewPos := lHeight; end;
3. 处理ListView宽度变化
当ListView宽度改变时,Item高度可能需要重新计算,需更新缓存:
procedure TForm1.ListViewResize(Sender: TObject); begin PreCalculateItemHeights(TListView(Sender), '你的自定义文本控件名称'); end;
额外优化建议
- 移除
ListViewAutoSize中的BeginUpdate/EndUpdate调用,该方法在OnUpdateObject触发时已处于ListView的更新周期内,额外包裹会降低性能。 - 若Item数量较多,可将预计算逻辑放在后台线程中执行,避免UI卡顿。
内容的提问来源于stack exchange,提问作者Marko
相关产品推荐
相关产品推荐

