Delphi で TPathAnimation を使ってみた

FireMonkey には、時間の経過と共にプロパティの値を変更するアニメーションコンポーネントがあります
アニメーションについては、以前[「プロパティ値によるアニメーションの違いを調べてみた」](https://qiita.com/CYonezawa/items/6d0f016fc8ea3afbe472)で、プロパティの値によって始点から終点までの動きが異なるかを紹介しました

アニメーションコンポーネントのほとんどは、一方方向に向って値を変化させるのですが、幾つかのものは一連の値に沿って変化できるという便利な特性を持っています
その中のひとつである [TPathAnimation](http://docwiki.embarcadero.com/Libraries/Tokyo/ja/FMX.Controls.TPathAnimation) を使ってみました

## サンプルアプリケーション
こんなサンプルを作成しました

- 1 Down のボタンをクリックすると、バーが 50 下に移動する
- 1 Down Bound のボタンをクリックするとバウンドするような動作でバーが 50 下に移動する
- New One のボタンをクリックすると、上からバーが落ちてきて初期状態にもどる

![AnimationBound1.gif](https://qiita-image-store.s3.amazonaws.com/0/164551/a28e80a6-a0fe-a63e-c421-497bc0c45ba8.gif)
![AnimationBound2.gif](https://qiita-image-store.s3.amazonaws.com/0/164551/a0e58dd6-433d-8460-0b61-cf25a5051455.gif)

## サンプルの設計画面とコード
設計画面はこちら
![AnimationBound.png](https://qiita-image-store.s3.amazonaws.com/0/164551/8237067c-5baa-fec4-b0c0-9cf99d3031e2.png)

設計時のポイントは、次の２つです

- FloatAnimation, PathAnimation 共にバーである Rectangle の子とすること 
- FloatAnimation の PropertyName プロパティは、値を変化させる Rectangle の Position.Y プロパティに設定すること

コードで記述している FloatAnimation のプロパティは、オブジェクトインスペクタ上で設定できますが、このサンプルでは比較のためにワザと記述しています

```pascal
unit Unit3;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  FMX.Objects, FMX.Layouts, FMX.Controls.Presentation, FMX.Ani;

type
  TForm3 = class(TForm)
    Button1: TButton;
    Layout1: TLayout;
    Layout2: TLayout;
    Button2: TButton;
    Rectangle1: TRectangle;
    Panel1: TPanel;
    FloatAnimation1: TFloatAnimation;
    PathAnimation1: TPathAnimation;
    Button3: TButton;
    FloatAnimation2: TFloatAnimation;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { private 宣言 }
    mCnt: Integer;
  public
    { public 宣言 }
  end;

var
  Form3: TForm3;

implementation

{$R *.fmx}

procedure TForm3.Button1Click(Sender: TObject);
begin
// 1 Down ボタン動作
  if mCnt > 4 then Exit;  // これ以上は Down できない

  mCnt := mCnt + 1;

  FloatAnimation2.Stop;                                     // アニメーションの終了
  FloatAnimation2.Duration := 2;
  FloatAnimation2.StartValue := Rectangle1.Position.Y + 0;  // 始点
  FloatAnimation2.StopValue := Rectangle1.Position.Y + 50;  // 終点
  FloatAnimation2.Start;                                    // アニメーションの開始
end;

procedure TForm3.Button2Click(Sender: TObject);
begin
// New One ボタン動作
  FloatAnimation1.Stop;                                    // アニメーションの終了
  FloatAnimation1.Duration := 1;
  FloatAnimation1.StartValue := -250;                      // 始点 (画面の外)
  FloatAnimation1.StopValue := 150;                        // 終点 (最初のバーの位置)
  FloatAnimation1.Start;                                   // アニメーションの開始
  mCnt := 0;
end;

procedure TForm3.Button3Click(Sender: TObject);
begin
//1 Down Bound ボタン動作
  if mCnt > 4 then Exit;  // これ以上は Down できない

  mCnt := mCnt + 1;

  PathAnimation1.StopAtCurrent;                           // アニメーションの終了
  PathAnimation1.Start;                                   // アニメーションの開始
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  mCnt := 0; //初期化
  PathAnimation1.Create(Self);
  PathAnimation1.Path.MoveTo(PointF(0,50));  // 移動する範囲を指定
  PathAnimation1.Path.LineTo(PointF(0,10));  // 途中座標の指定
  PathAnimation1.Path.LineTo(PointF(0,50));  // 途中座標の指定
  PathAnimation1.Path.LineTo(PointF(0,20));  // 途中座標の指定
  PathAnimation1.Path.LineTo(PointF(0,50));  // 途中座標の指定
  PathAnimation1.Path.LineTo(PointF(0,30));  // 途中座標の指定
  PathAnimation1.Path.ClosePath;             // 座標の指定終了
  PathAnimation1.Duration := 2;
end;

end.
```

## 解説
FloatAnimation の場合は一方方向への値の変化しかできないので、もし、同じようにバウンドさせるような動作を行なうのであれば

- 0 → 50 に移動する座標を定めて Start, Stop
- 50 → 10 に移動する座標を定めて Start, Stop
- 10 → 50 に移動する座標を定めて Start, Stop
- 50 → 20 に移動する座標を定めて Start, Stop
- 20 → 50 に移動する座標を定めて Start, Stop
- 50 → 30 に移動する座標を定めて Start, Stop
- 30 → 50 に移動する座標を定めて Start, Stop

というコードを書かねばならない（又は上記の設定をした FloatAnimation を用意して、順番に動作させる）
PathAnimation の場合は、最初に移動する範囲を MoveTo で指定して、LineTo で、その範囲内で更に移動する座標を指定できる
このサンプルの場合

- MoveTo で 0 → 50 の移動を指定する
- この移動の間に動かしたい座標があれば LineTo を使って座標を複数指定する（座標は MoveToで指定した座標から外れても OK）
- すべての座標の指定が終わったら ClosePath で座標指定終了とする
- この移動をどのくらいの時間をかけて行なうかを Duration に指定する
- 使うときは、作成した PathAnimation を Start させるだけ

ギミック的な動きをさせるのに利用できますね