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.