Spinning Icons to Visually Queue Load States Using True Type Font Pack Font Awesome

Posted by on in Tutorial

Keeping the end user informed about what your application is up to can be the difference between retention and abandonment. Using spinning icons to visually queue the end user that the app is in a load state will ensure that your end user knows that the application is working on something. The last thing your app should do in this situation is freeze the UI until the processes has completed. 

This blog post will demonstrate the use of System.Threading to keep the UI responsive while simulating a load state.

Video not found or Youtube service not available

Project Files

Download the project files. C++, and compatable with Android, iOS, OSX, and Windows.


Deploying True Type Fonts

I recently published a blog post and video which outlines the steps needed to build a multi-device Android and iOS application that uses a true type font, like Font Awesome, for the purpose of iconography. Using a font for icons has advantages over using raster image files in that they are light weight and vector based so they scale up nicely to high resolutions.

For complete insturctions on how to deploy an Android or iOS application with custom loaded True Type Fonts, check out my blog post entitled True Type Font Iconography for Android and iOS Apps.



Here is a screenshot of the Project Structure.


To create the spinning icon, a TFloatAnimation is attached to the TLabel and named as SpinAnim. The Loop and Enabled properties for the SpinAnim are set to True. The StartValue is set to 0 and the StopValue is set to 360. This will endlessly spin the Label around 360 degrees.

A TCircle contains the Label and has it's own set of TFloatAnimation components for moving the circle (and the label it contains) down from the top of the screen and then back up off the screen.

A TButton (Button1) is used to initate a simulated load event.

A TComboBox (ComboBox1) allows the selection of different Font Awesome spinner icons.



A map is used to connect the TComboBox selection to the set of Font Awesome icon variables loaded in from FontAwesomeCodes.h (included in project file download).

__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
    //- map font awesome combo box items to the values in FontAwesomeCodes.h
    FontAwesomeIcons["Circle Notch"]    = fa_circle_o_notch;
    FontAwesomeIcons["Cog"]             = fa_cog;
    FontAwesomeIcons["Gear"]            = fa_gear;
    FontAwesomeIcons["Refresh"]         = fa_refresh;
    FontAwesomeIcons["Spinner"]         = fa_spinner;
    //- Hide the spinner until we need it
    Circle1->Visible             = false;
    //- set animation values relative to circle height
    MoveDownAnim->StartValue = -1 * Circle1->Height;
    MoveDownAnim->StopValue      = Circle1->Height / 2;
    MoveUpAnim->StartValue       = Circle1->Height / 2;
    MoveUpAnim->StopValue    = -1 * Circle1->Height;
    //- set inital spinner icon
    Label1->Text = FontAwesomeIcons[ ComboBox1->Selected->Text ];

ComboBox Change

void __fastcall TForm2::ComboBox1Change(TObject *Sender)
    //- because this application uses threads, the combo box will remain
    //      active during the load state. It is possible to change the loading
    //      icon while the simulated load is running.
    Label1->Text = FontAwesomeIcons[ ComboBox1->Selected->Text ];


Button Click

When the button is clicked, a new TTask is started. This action will simulate a loading sequence that will take 5 seconds. Using a TTask in this context will prevent the UI from locking up. In reality, this could be a RESTful API call, loading a media asset, or anything else that would potentially lock the UI.

void __fastcall TForm2::Button1Click(TObject *Sender)
    //- reset animations
    MoveDownAnim->Enabled        = false;
    MoveUpAnim->Enabled          = false;
    //- initiate UI state within the main thread and not in the task itself
    Button1->Enabled             = false;
    Circle1->Visible             = true;
    //- reveal spinning icon container
    MoveDownAnim->Enabled        = true;
    //- fire off a new taask to simulate a load event
    //      here we pass in the animation to run at the end of
    //      the simulated loading task along with UI elements we want to
    //      disable.
    TTask::Run( _di_TProc(new TCppTask(5000, MoveUpAnim, Button1)) );


Move Up Animation Finish

When the MoveUpAnim has completed the Circle should be hidden. This helps keeps the loading icon off the screen until it is actually needed.

void __fastcall TForm2::MoveUpAnimFinish(TObject *Sender)
    //- hide the circle and spinner icon after the animation is finished
    Circle1->Visible = false;



Threading a Simulated Load State

For more information on how to use the System.Threading library please check out the following resources:

class TCppSync : public TCppInterfacedObject<TThreadProcedure> {
  int sleepTime;//lValue;
  TFloatAnimation *FloatAnimation;
  TButton *Button;
  TCppSync(int l, TFloatAnimation *fa, TButton *b) : sleepTime(l), FloatAnimation(fa), Button(b)
  void __fastcall Invoke() {
    //- fire off the animation passed in to this task
    FloatAnimation->Enabled  = true;
    //- unlock the UI, simulated load state is finished.
    Button->Enabled          = true;
class TCppTask : public TCppInterfacedObject<TProc> {
  int sleepTime;//lValue;
  TFloatAnimation *FloatAnimation;
  TButton *Button;
  TCppTask(int l, TFloatAnimation *fa, TButton *b) : sleepTime(l), FloatAnimation(fa), Button(b)
  void __fastcall Invoke() {
    //- simulate a load event that takes some amount of seconds
    //- the task has finished, pass control back to the main thread with synchronize
    TThread::Synchronize(0, _di_TThreadProcedure(new TCppSync(sleepTime, FloatAnimation, Button)));



Tags: Appmethod

Gold User, Rank: 8, Points: 399
Brian Alexakis is a Product Marketing Manager at Embarcadero Technologies. He is focused on leveraging the connected world of technology to build new experiences for the Internet of Things.


Check out more tips and tricks in this development video: