Variable Item Height with TListView in 10.1 Berlin

by Jun 10, 2016

During a recent webinar, we received a question on how to create a list in a FireMonkey multi-device application using RAD Studio Berlin where the item height automatically adjusts itself depending on the content.

We have a great new demo that shows you how to calculate text dimensions and how to dynamically adjust the item height in a ListView so that the text fits inside.

When ListView items are just being created, the drawable objects that comprise the visual presentation of the content are not created immediately. This usually happens when the ListView is being painted for the first time.

Appearances specify views and their properties that are common for all items. However, to modify individual items, the drawable objects that form the views should be manipulated directly. They can be accessed at any time, however trying to manipulate them before the appearance has done its job would not make much sense because all changes made before that will be overwritten by the appearance.

In order to access the drawable objects at the correct time, there is an event called TListView.OnUpdateObjects which is called for every item after its view has been updated. This demo implements a handler for it and calculates item dimensions based on available width and length of the text that the item contains. To liven up the visual aspect of the demo, the size and weight of the font is also altered in the same handler.

procedure TVariableHeight.ListView1UpdateObjects(const Sender: TObject;
  const AItem: TListViewItem);
var
  Drawable: TListItemText;
  SizeImg: TListItemImage;
  Text: string;
  AvailableWidth: Single;
begin
  SizeImg := TListItemImage(AItem.View.FindDrawable('imgSize'));
  AvailableWidth := TListView(Sender).Width - TListView(Sender).ItemSpaces.Left
    - TListView(Sender).ItemSpaces.Right - SizeImg.Width;

  // Find the text drawable which is used to calcualte item size.
  // For dynamic appearance, use item name.
  // For classic appearances use TListViewItem.TObjectNames.Text
  // Drawable := TListItemText(AItem.View.FindDrawable(TListViewItem.TObjectNames.Text));
  Drawable := TListItemText(AItem.View.FindDrawable('txtMain'));
  Text := Drawable.Text;

  // Randomize the font when updating for the first time
  if Drawable.TagFloat = 0 then
  begin
    Drawable.Font.Size := 1; // Ensure that default font sizes do not play against us
    Drawable.Font.Size := 10 + Random(4) * 4;

    Drawable.TagFloat := Drawable.Font.Size;
    if Text.Length < 100 then
      Drawable.Font.Style := [TFontStyle.fsBold];
  end;

  // Calculate item height based on text in the drawable
  AItem.Height := GetTextHeight(Drawable, AvailableWidth, Text);
  Drawable.Height := AItem.Height;
  Drawable.Width := AvailableWidth;

  SizeImg.OwnsBitmap := False;
  SizeImg.Bitmap := GetDimensionBitmap(SizeImg.Width, AItem.Height);
end;

The demo uses DynamicAppearance for the items, but the same approach can be used using the classic appearances, predefined or user defined.

You can access the demo here:

https://sourceforge.net/p/radstudiodemos/code/HEAD/tree/branches/RADStudio_Berlin/Object%20Pascal/Multi-Device%20Samples/User%20Interface/ListView/VariableHeightItems/

 

 [DownloadButton Product=’RAD’ Caption=’Download a Free RAD Studio Berlin Trial today!’]