1

I'm using this code to add an item to a listbox, but I can't figure out how to dynamically resize the height of the item to fit the text:

procedure TmForm.AddItemBtnClick(Sender: TObject);
var
  Item: TListBoxItem;
begin
  Item := TListBoxItem.Create(nil);
  Item.Parent := SomeListBox;
  Item.StyleLookup := 'listboxitemstyle';
  Item.Text :=
              'Pe cararea lunga scurta se ducea un om venind, si-n tacerea lui ' +
              'profunda se auzea borborosind. Cantr-o noapte intunecoasa soarel' +
              'e lucea pe cer, iara eu cu barca in casa ma plimbam ca un boier.';
  Item.WordWrap := true;
  Item.StyledSettings := [TStyledSetting.ssFamily] + [TStyledSetting.ssStyle] + [TStyledSetting.ssFontColor];
  Item.Font.Size := 14;
end;

I tried using the code from this example (modified for TListBoxItem), but it didn't work.

Edit: The height of the ListBoxItem can be set by just adding Item.Height := 100; at the end of the code above, but I need to know the height of text to decide what size the ListBoxItem needs to be, so to clarify my question, how do I get the height of the text in the list box item?

Community
  • 1
  • 1
ioan ghip
  • 1,202
  • 2
  • 16
  • 27

4 Answers4

1

Pop your resizing code in the OnApplyStyleLookup event.

Written off the top of my head and way past bedtime:

procedure TForm1.ListBoxItemApplyStyleLookup(Sender: TObject);
var O: TFMXObject;
begin
  O := (Sender as TListBoxItem).FindStyleResource('text');
  if O is TText then
    (Sender as TListBoxItem).Height := (O as TText).Height;
end;

You will, of course, need to set the event for every item you create.

Mike Sutton
  • 4,191
  • 4
  • 29
  • 42
  • I added to my code Item.OnApplyStyleLookup := ListBoxItemApplyStyleLookup; and the code you posted but the results are the same, actually the code in the ListBoxItemApplyStyleLookup is never reached. – ioan ghip Jan 27 '14 at 05:53
  • We cannot manually set Height for ListItem this way, because for mobile platforms firemonkey in style fixes height of item, so you can not directly change height. – Yaroslav Brovin Jan 27 '14 at 12:09
  • @Yaroslav, that's only for certain controls such as edits and buttons. There are other controls where the height can be set manually. – Mike Sutton Jan 27 '14 at 19:57
  • @ioan, Is the item actually being displayed? The style is only set once a control appears on screen. – Mike Sutton Jan 27 '14 at 19:59
  • @ioan. My tests show you need to set the event handler as the very first thing you do after creating the item It will then work fine. – Mike Sutton Jan 27 '14 at 20:07
  • After playing with this, it appears that the text never word wraps properly even if you manually set a larger height for the item. Either I'm doing something wrong or there's a bug there somewhere. – Mike Sutton Jan 27 '14 at 20:50
  • @MikeSutton Yeah, doesn't work for me either. I think I'm going to move away from the ListBox and use the ScrollBox with my own custom items. – ioan ghip Jan 27 '14 at 23:29
  • I'm having similar issues where setting item height does not work in XE7: http://stackoverflow.com/questions/29436085/hide-empty-space-behind-invisible-list-box-items – Jerry Dodge Apr 03 '15 at 19:42
1

As mentioned by Mike Sutton, it can be done OnApplyStyleLookup event. I do it using a TTextLayout :

uses 
... ,FMX.TextLayout;

procedure TfrmForm1.ListBoxItem1ApplyStyleLookup(Sender: TObject);
var
  myLayout: TTextLayout;
  aPoint: TPointF;
begin

  myLayout := TTextLayoutManager.DefaultTextLayout.Create;
  myLayout.BeginUpdate;

  // Setting the layout MaxSize
  aPoint.X := ListBoxItem1.Width;
  aPoint.Y := TfrmForm1.Height;
  myLayout.MaxSize := aPoint;

  myLayout.Text := ListBoxItem1.Text;
  myLayout.WordWrap := True ;
  myLayout.Font := ListBoxItem1.Font;
  myLayout.HorizontalAlign := ListBoxItem1.TextSettings.HorzAlign;
  myLayout.VerticalAlign := ListBoxItem1.TextSettings.VertAlign;
  myLayout.Padding := ListBoxItem1.Padding;
  // set other properties as needed        

  myLayout.EndUpdate;

  ListBoxItem1.Height := Trunc(myLayout.TextHeight) + 3 ; // +3px to be sure to see entire text

end;

Note that MaxSize is limitating. For example, aPoint.Y will limit the final TextHeight. You should set it large because, whatever TextHeight should be, if myLayout.TextHeight is larger than myLayout.MaxSize.Y then myLayout.TextHeight will be set to myLayout.MaxSize.Y.

Here's a list of TTextLayout properties.

0

Here is the Mike Sutton's code, improved and tested by me. Works for case of an Item with a Detail text (.ItemData.Detail). The variant with TextLayout did not work for me.

This code is tested for Windows and Android application.

procedure TTestForm.ListBoxItem1ApplyStyleLookup(Sender: TObject);
var item: TListBoxItem absolute Sender;

  function CalcHeight( SubStyle: String ): Single;
  var Obj: TFMXObject; T: TText absolute Obj;
  begin
    Obj := item.FindStyleResource(SubStyle);
    if Obj is TText
    then Result := T.Canvas.TextHeight(T.Text)
                 + T.Margins.Top + T.Margins.Bottom
                 + T.Padding.Top + T.Padding.Bottom
    else Result := 0;
  end;

begin
  item.Height := CalcHeight('text')
               + CalcHeight('detail');
end;
-1

There are one important thing about changing size of control: "For mobile platform, firemonkey fix height and with some controls". Because:

  1. UI Style Guidline for each platform define rules about size of standart controls.
  2. Firemonkey uses raster style, so you cannot change some control size, because you will lost a quality of view

However, you can remove this contraints. Look at the my solution this (Auto translated with Google): Can not increase the height TProgressBar

This article about TProgressBar, But you can use this approach also for a TListBoxItem.

Yaroslav Brovin
  • 964
  • 6
  • 19
  • 1
    There isn't a FixedHeight field for the ListBoxItem and the height of the item can be set bu just adding Item.Height := 95; in the code, but I need to know the height of the text to know what value to set the ListBoxItem height. – ioan ghip Jan 27 '14 at 17:43