Table of Contents

Custom Item Classes

Most responsive lists are built entirely from conditions, templates, and the built-in item properties (HeaderText, Content, FooterText, Values). Reach for a custom item class only when an item needs extra state that the built-in properties cannot hold, or when it must draw something the template system does not express — a status badge, a progress ring, a sparkline, or a state-dependent overlay. A custom item class lets you add published properties for that extra state and override DrawItem to paint it on top of the standard template, header, and footer rendering. You opt in by deriving a list class that overrides GetItemClass so every item the list creates is your custom type. This guide shows how to define the class, draw custom content, and combine both with the responsive conditions that reflow the list across breakpoints.

Define a Custom Item Class

Derive from TResponsiveListItem and add the published properties your item needs. Publishing the property keeps it available to the designer and to streaming. Then derive a list class from TTMSFNCResponsiveList and override GetItemClass to return your item type — this is the hook the list uses when it creates new items, so every Items.Add produces an instance of your class.

type
  TStatusResponsiveListItem = class(TResponsiveListItem)
  private
    FStatusText: string;
  published
    property StatusText: string read FStatusText write FStatusText;
  end;

  TStatusResponsiveList = class(TTMSFNCResponsiveList)
  protected
    function GetItemClass: TCollectionItemClass; override;
  end;

Custom Drawing

Override the item DrawItem method to paint additional content after the inherited rendering has drawn the standard template, header, and footer. Call inherited first so the built-in visuals are in place, then draw only the extra state — keep custom drawing focused on what the templates cannot express.

type
  TStatusResponsiveListItem = class(TResponsiveListItem)
  private
    FStatusText: string;
  protected
    procedure DrawItem(AGraphics: TTMSFNCGraphics; ATemplate, AHeaderTemplate,
      AFooterTemplate: string; ARect: TRect; Focus: Boolean); override;
  published
    property StatusText: string read FStatusText write FStatusText;
  end;

  TStatusResponsiveList = class(TTMSFNCResponsiveList)
  protected
    function GetItemClass: TCollectionItemClass; override;
  end;

procedure TStatusResponsiveListItem.DrawItem(AGraphics: TTMSFNCGraphics;
  ATemplate, AHeaderTemplate, AFooterTemplate: string; ARect: TRect;
  Focus: Boolean);
begin
  inherited DrawItem(AGraphics, ATemplate, AHeaderTemplate, AFooterTemplate,
    ARect, Focus);
  AGraphics.DrawText(ARect, StatusText);
end;

function TStatusResponsiveList.GetItemClass: TCollectionItemClass;
begin
  Result := TStatusResponsiveListItem;
end;

Keep custom drawing focused on item-specific visuals. Use normal conditions and templates for layout changes, then draw only the extra visual state that is not covered by the built-in item properties.

Combining custom drawing with responsive conditions

A custom item class does not replace responsive layout — it composes with it. The list still reflows your custom items across breakpoints. The following example defines a status item that paints its StatusText, then configures single-column and three-column conditions and adds items that set the custom state:

type
  TStatusResponsiveListItem = class(TResponsiveListItem)
  private
    FStatusText: string;
  protected
    procedure DrawItem(AGraphics: TTMSFNCGraphics; ATemplate, AHeaderTemplate,
      AFooterTemplate: string; ARect: TRect; Focus: Boolean); override;
  published
    property StatusText: string read FStatusText write FStatusText;
  end;

  TStatusResponsiveList = class(TTMSFNCResponsiveList)
  protected
    function GetItemClass: TCollectionItemClass; override;
  end;

procedure TStatusResponsiveListItem.DrawItem(AGraphics: TTMSFNCGraphics;
  ATemplate, AHeaderTemplate, AFooterTemplate: string; ARect: TRect;
  Focus: Boolean);
begin
  inherited DrawItem(AGraphics, ATemplate, AHeaderTemplate, AFooterTemplate,
    ARect, Focus);
  if StatusText <> '' then
    AGraphics.DrawText(ARect, StatusText);
end;

function TStatusResponsiveList.GetItemClass: TCollectionItemClass;
begin
  Result := TStatusResponsiveListItem;
end;

{ Custom drawing (above) reflowed by responsive conditions (below): }
procedure TForm1.ConfigureStatusList(AList: TStatusResponsiveList);
var
  Condition: TResponsiveCondition;
  Item: TResponsiveListItem;
begin
  AList.Conditions.Clear;

  Condition := AList.Conditions.Add;
  Condition.WidthFrom := 0;
  Condition.WidthTo := 360;
  Condition.Columns := 1;
  Condition.ItemHeight := 120;

  Condition := AList.Conditions.Add;
  Condition.WidthFrom := 361;
  Condition.WidthTo := -1;
  Condition.Columns := 3;
  Condition.ItemHeight := 120;

  AList.Items.Clear;

  Item := AList.Items.Add;
  Item.HeaderText := 'Support';
  Item.Content := '<b>Open tickets</b><br>12 items need review';
  (Item as TStatusResponsiveListItem).StatusText := 'SLA breach risk';

  Item := AList.Items.Add;
  Item.HeaderText := 'Sales';
  Item.Content := '<b>Pipeline</b><br>4 opportunities closing';
  (Item as TStatusResponsiveListItem).StatusText := 'On track';
end;

Common pitfalls

  • Forgetting GetItemClass. Adding a custom item class is not enough — the list only creates your type if a list descendant overrides GetItemClass. Without it, Items.Add returns a plain TResponsiveListItem and the cast in your setup code fails.
  • Drawing before inherited. Call inherited DrawItem(...) first; otherwise the standard template paints over your custom content.
  • Heavy work in DrawItem. DrawItem runs on every repaint and every reflow. Compute values ahead of time and store them on the item rather than recalculating inside the draw method.

See Also