Table of Contents

Animation and Overlay

Waiting indicators should communicate that work is active without suggesting a precise completion time. Use OverlayParent when users should not interact with the parent area while the operation is running.

Overlay a Busy Region

Set OverlayParent to cover the parent control while the indicator is active. This is useful for panels, dialogs, or data regions that should pause interaction while data loads.

procedure TForm1.StartLoading;
begin
  TMSFNCWaitingIndicator1.OverlayParent := True;
  TMSFNCWaitingIndicator1.AnimationSpeed := 1.0;
  TMSFNCWaitingIndicator1.Active := True;
end;

procedure TForm1.FinishLoading;
begin
  TMSFNCWaitingIndicator1.Active := False;
end;

Tune the Appearance

Use AnimationSpeed to match the pace of the application. The Appearance object controls the indicator and movement shape; choose a shape that remains readable at the component size.

procedure TForm1.ConfigureWaitingIndicator;
begin
  TMSFNCWaitingIndicator1.Appearance.IndicatorShape := wisCircle;
  TMSFNCWaitingIndicator1.Appearance.MoveShape := wmsCircle;
  TMSFNCWaitingIndicator1.AnimationSpeed := 0.8;
  TMSFNCWaitingIndicator1.OverlayParent := True;
end;

Drawing Hooks

OnBeforeDrawIndicator and OnBeforeDrawOverlay can suppress default drawing for specialized scenarios. Use these hooks sparingly; most applications should style the indicator through Appearance.

Combining overlay, tuned appearance, and a drawing hook

The following example overlays a panel while data loads, slows the animation to match a smooth loading feel, and uses OnBeforeDrawOverlay to tint the overlay semi-transparent:

procedure TForm1.LoadData;
begin
  // cover the data panel
  TMSFNCWaitingIndicator1.OverlayParent := DataPanel;
  TMSFNCWaitingIndicator1.AnimationSpeed := 40;  // slower = calmer feel
  TMSFNCWaitingIndicator1.Appearance.IndicatorShape := wisCircle;
  TMSFNCWaitingIndicator1.Visible := True;

  TTask.Run(procedure
  begin
    // ... fetch data ...
    TThread.Synchronize(nil, procedure
    begin
      DataPanel.Refresh;
      TMSFNCWaitingIndicator1.Visible := False;
    end);
  end);
end;

procedure TForm1.TMSFNCWaitingIndicator1BeforeDrawOverlay(
  Sender: TObject; AGraphics: TTMSFNCGraphics; ARect: TRectF;
  var ADefaultDraw: Boolean);
begin
  // semi-transparent dark overlay instead of the default
  AGraphics.Fill.Color := MakeColor(0, 0, 0, 160);
  AGraphics.DrawRectangle(ARect);
  ADefaultDraw := False;
end;

High-DPI indicator artwork

The indicator rescales the metrics it owns — Appearance.IndicatorStroke.Width and Appearance.OverlayStroke.Width — whenever the display scale changes, and it does so in the form designer as well as at run time, so a form authored on a high-DPI development machine keeps the same design values. Bitmaps are the exception. A wisImage indicator draws Appearance.IndicatorBitmap for each of its Indicators, plus Appearance.CenterBitmap in the middle; both are single TTMSFNCBitmap surfaces with a fixed pixel count, so artwork authored for a 100% display turns soft at 150% or 200%. Read the control's ResourceScaleFactor (the display scale it resolves image resources against) and load the matching variant.

uses
  System.SysUtils, FMX.TMSFNCUtils, FMX.TMSFNCWaitingIndicator;

procedure TForm1.ConfigureWaitingIndicatorForDisplayScale;
var
  Suffix: string;
begin
  { ResourceScaleFactor is the display scale the control resolves image
    resources against: 1.0 at 96 DPI, 1.5 at 144 DPI, 2.0 at 192 DPI. }
  if TMSFNCWaitingIndicator1.ResourceScaleFactor >= 2 then
    Suffix := '@2x'
  else if TMSFNCWaitingIndicator1.ResourceScaleFactor >= 1.5 then
    Suffix := '@1.5x'
  else
    Suffix := '';

  TMSFNCWaitingIndicator1.BeginUpdate;
  try
    { wisImage draws IndicatorBitmap for every indicator, and CenterBitmap
      once in the middle. Both are single TTMSFNCBitmap surfaces, so the
      artwork has to match the pixel density of the display. }
    TMSFNCWaitingIndicator1.Appearance.IndicatorShape := wisImage;
    TMSFNCWaitingIndicator1.Appearance.IndicatorBitmap.LoadFromFile('spinner-dot' + Suffix + '.png');
    TMSFNCWaitingIndicator1.Appearance.CenterBitmap.LoadFromFile('spinner-logo' + Suffix + '.png');
    TMSFNCWaitingIndicator1.Appearance.Indicators := 8;
    TMSFNCWaitingIndicator1.Appearance.MoveShape := wmsCircle;

    { The indicator and overlay stroke widths are rescaled by the control
      itself, at design time as well as at run time, so leave them at their
      design values. }
    TMSFNCWaitingIndicator1.Appearance.IndicatorStroke.Width := 1;
    TMSFNCWaitingIndicator1.Appearance.OverlayStroke.Width := 1;
  finally
    TMSFNCWaitingIndicator1.EndUpdate;
  end;

  if TTMSFNCUtils.IsHighDPIScale(Self) then
    StatusLabel.Text := Format('Indicator artwork loaded at %.2fx',
      [TTMSFNCUtils.GetDPIScale(Self)]);
end;

The drawn shapes (wisCircle, wisSquare, wisProgress) need none of this — they are painted from the stroke and fill settings and follow the control's bounds — so reach for wisImage only when the animation has to use branded artwork.

See Also