2

I'm considering to put a loading animation and a progress arc in a single object (like WhatsApp when loading a record), so I thought it was better to use TArc and TFloatAnimation, since I can control the StartAngle and EndAngle of the stroke. I'm trying to make the Google loading spinner logic but I'm very confused, it looks like there is a FloatAnimation with "linear" interpolation property that controls one of the angles and another one that looks to have a exponential or sinusoidal interpolation that start/end very fast and I can't see it, anyone had already tried to reproduce it? Thanks.

Image from web: enter image description here

Maurício Lima
  • 504
  • 6
  • 20
  • 3
    I actually just recently did something similar, and encapsulated it inside of a Firemonkey control... https://pastebin.com/MUFyQNDu Not the same thing exactly, this is more of a progress indicator (value / max), but it can help you get moving in the right direction. – Jerry Dodge Oct 05 '17 at 19:23
  • @Jerry Dodge Thank you Jerry. So far I've been playing with two FloatAnimation's (StartAngle and EndAngle) properties trying to reach this spinner. – Maurício Lima Oct 05 '17 at 19:43

1 Answers1

8

Requirement to make this:

I find that you calling it a spinner is wrong. It's a spring in a harmonic motion plus a rotation effect.

This is the effect if you don't know it

enter image description here

You could read about it in Wikipedia (Warning it's written in French)

Now to solve this problem you need to define an array which will hold the values of the potential energy required to compress and stretch the spring.

PotentialEnergy: array[0..10] of Single;

The animation you are seeing is this

enter image description here

the spring stretching then getting compressed again. And in order to make it rotate we will define a rotation speed

RotationSpeed : Single;  

and the finale animation would look like this

enter image description here

This is final implementation of this animation:

var
  Form6: TForm6;
  Increment: Integer;
  PotentialEnergy: array[0..10] of Single;
  ReverseMotion : Boolean;
  RotationSpeed : Single;
implementation

{$R *.fmx}

procedure SetArray(var aData: array of Single; const aSource: array of Single);
var
  I: Integer;
begin
  for I := Low(aSource) to High(aSource) do
    begin
    aData[I] := aSource[I];
    end;
end;

procedure TForm6.Button1Click(Sender: TObject);
begin
  SetArray(PotentialEnergy, [5, 64, 48, 32, 24, 16, 14, 10, 8, 7]);
  Increment := -1;
  ReverseMotion := False;
  arc1.StartAngle := 0;
  arc1.EndAngle := 1;
  RotationSpeed := strtoint(edit1.text); // Degrees per 0.1 second
  timer1.Enabled := True;
end;

procedure TForm6.Timer1Timer(Sender: TObject);
begin
  if not ReverseMotion then
    begin
    Inc(Increment);
    arc1.EndAngle := arc1.EndAngle + PotentialEnergy[Increment];
    arc1.StartAngle := arc1.StartAngle + RotationSpeed;
    end
  else
    begin
    Inc(Increment);
    arc1.StartAngle := arc1.StartAngle + PotentialEnergy[Increment] + RotationSpeed;
    arc1.EndAngle := arc1.EndAngle - PotentialEnergy[Increment];
    end;

 if (Increment > 10)then
    begin
    ReverseMotion  := not ReverseMotion;
    Increment := -1;
    end;
end;

Also you could create animation like these

enter image description here

enter image description here


Update: after some synchronization(don't ask me how)

I found the could be exact replica of that google animation

Steps:

  • set the timer to 30 ms.
  • set the rotation speed to 5.
  • set the height and width of the TArc to 102.
  • set potential energy to this [23, 40, 39, 31, 23, 18, 15, 13, 11, 9, 7, 6, 5, 4, 4].

and the result is this (the google animation on the right)

enter image description here

Nasreddine Galfout
  • 2,550
  • 2
  • 18
  • 36
  • Awesome! I wasn't able to realize it for three days. I just have one doubt, how I would change the values of Potential Energy to fit well on a 16 ms TTimer? It seems very fast. – Maurício Lima Oct 09 '17 at 01:26
  • @MaurícioLima What do you mean by 16 ms TTimer? – Nasreddine Galfout Oct 09 '17 at 02:30
  • Using a 16ms TTimer so you can achieve 60 fps animation without the EndAngle animation being so fast. I think it's better to increase the array values from 10 to 20 or more and build a graph, but I don't know how to calculate when the sum of the values must be near 360, so the animation will be very genuine. – Maurício Lima Oct 09 '17 at 02:41
  • I made this array: `[3, 7, 15, 26, 37, 48, 36, 31, 25, 21, 16, 14, 11, 9, 8, 7, 6, 5, 4, 3,3, 2, 2, 2, 1, 1, 1,1]);` And change the `TTimer` line to: `if (Increment > 28)then` And set a speed of `8`. Thats the closest I could reach. Thank you Nasreddine! – Maurício Lima Oct 09 '17 at 02:57
  • I'm glad that you are trying to modify this to get something that is better for you. The result above are based on the dissection of the GIF using not allowed to share software. – Nasreddine Galfout Oct 09 '17 at 21:26