Delphi で Pull To Refresh

# PullToRefresh

Delphi で簡単に PullToRefresh しようよ～（ジョイマン風に）

## PullToRefresh とは

上から下に引っ張ると表示内容が更新される機能です。

## ListView PullToRefresh

[TListView](http://docwiki.embarcadero.com/Libraries/Rio/ja/FMX.ListView.TListView) には [PullToReflesh](http://docwiki.embarcadero.com/Libraries/Rio/ja/FMX.ListView.TListViewBase.PullToRefresh) が機能として提供されています。

PullToRefresh の所にも書いてありますが、使い方は

1. PullToRefresh プロパティを True にする
2. [OnPullRefresh](http://docwiki.embarcadero.com/Libraries/Rio/ja/FMX.ListView.TListViewBase.OnPullRefresh) イベントハンドラに更新する内容を記載する
3. 更新が終わったら StopPullReflesh を呼ぶ

という感じです。

<img width="480" alt="Object.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/9e7ef6d4-9167-4cb8-14d9-9539eeba63ea.png">

```pascal:OnPullRefresh
procedure TfrmMain.ListView1PullRefresh(Sender: TObject);
begin
  CreateRandomValue; // ListView にランダムな値を設定するメソッド
  ListView1.StopPullRefresh; // iOS の場合に待機アニメーションが停止される
end;
```

また [PullRefreshWait](http://docwiki.embarcadero.com/Libraries/Rio/ja/FMX.ListView.TListViewBase.OnPullRefresh) というプロパティがあります。
このプロパティは iOS でしか効果がありません。
このプロパティを True にすると待機アニメーションが自動的に止まるようになります。
このプロパティを False にした場合は、コードで示したように StopPullRefresh を手動で呼び出します。
本来、データの更新というのは時間が掛かる物なので、PullRefreshWait を True にする機会は少ないかも知れません。

実際に動かすとこんな感じ

**iOS**
<img width="240" alt="P2RSample.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/d7fc54f8-8fa5-de03-9a05-ebe5d762f932.gif">

**Android**
<img width="240" alt="Xperia.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/d72016fe-65a7-ccda-dd27-5a69f410a3b2.gif">

# ListView 以外ではどうする？

ここからが本題！
ListView 以外の時にこの動作をさせたくても、そんなコントロールは無いのでした。

ということで Top に [TLayout](http://docwiki.embarcadero.com/Libraries/Rio/ja/FMX.Layouts.TLayout) を置いて OnMouseDown, OnMouseMove, OnMouseUp で引っ張り出せるようにしてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/0e748f74-018c-af03-fac9-2a80222cb5e3.png)

## 利点
この方法の利点は全部の OS で使えるということです。
先に上げた TListView の方法だとモバイルだけ。しかも Android の表示はそもそも Pull 感が無くて超解りづらい…

## 欠点
引っ張り出せるようにするために上部に少しコントロールを出しておかないといけない、というところです。
なので、画面上部にユーザーが操作する UI を置いておくことができません。

## 実装
これを実装した [PK.GUI.PullToRefreshLayout](https://gist.github.com/freeonterminate/8381f935e61b0e36c37c442503612889) を作成しました。
TPullToRefreshLayout を使うコードは↓こんな感じ

```pascal
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  FP2RLayout := TPullToRefreshLayout.Create(Self); // FP2RLayout は TPullToRefreshLayout として定義
  FP2RLayout.MaxPullingLen := 80; // どこまで引っ張り出せるか

  FP2RLayout.BoundsRect := Layout1.BoundsRect; // "PullToRefresh Sample" とあるエリアと同じ位置にする
  FP2RLayout.Parent := Self;
  FP2RLayout.BringToFront; // 最前面に持ってきて触れるようにする

  Path1.Parent := FP2RLayout; // 矢印を表示している Path を載せる

  FP2RLayout.OnRefresh := P2RLayoutRefresh; // イベントハンドラ

  CreateRandomValue;
end;

procedure TfrmMain.P2RLayoutRefresh(Sender: TObject);
begin
  CreateRandomValue; // 更新
end;
```

コレを使うと↓のような動作になります！

**Windows**
<img width="320" alt="P2RSample.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/c84146aa-e21f-b314-9ebd-fb0c97763b21.gif">

**macOS**
<img width="320" alt="P2RSample.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/7740f1eb-fd1c-35d6-e4d5-64a5ba8f591e.gif">


**iOS**
<img width="320" alt="P2RSample.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/44a1c7e6-7000-cbfb-ee10-400ae7c2cd9a.gif">

**Android**
<img width="320" alt="P2RSample.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/9587ac55-35a9-8f55-4d7a-030bedf8a44b.gif">

# まとめ
元から用意されている場合はそれを使って、用意されていない場合は工夫することが大事ですね！