#はじめに
前回に続いてFireMonkey初心者による初心者向け記事となります。
Delphiでスマートフォンアプリが作れる!と意気込んでみたものの、いざ作り出すとスマートフォンっぽいUIってどんなだっけ?となりまして。まずは既存のものを真似をするのがいいかなと思い至りました。
そんなわけで(?)、TVertScrollBoxを利用した作例を二つ、紹介したいと思います。
##例1:Twitterの上部エリアを再現する
Twitterを眺めているとチラチラ視界に入るアイツ
###やり方
図のような親子構造でコントロールを配置し、FormのOnCreate
イベントでListView
コントロールの高さを親コントロールの高さ(今回はForm1.ClientHeight)に設定するだけです。
(ListViewの仮データとしてPrototypeBindSourceを使用しています。詳細はこちら)
※親コントロールにMargin
、Padding
の設定をしている場合、その考慮も必要です。
※TabControlが親の場合、高さの計算はTabControl.Height-TabControl.TabHeight
になります。
###挙動を似せる
そのままでも結構それっぽいのですが、以下の機能が再現できていません。
・上部パネルが半分以上表示されていると、途中でスワイプを止めても全て表示される
・上部パネルが半分以上隠れていると、途中でスワイプを止めても全て隠れる
TVertScrollBox
のOnViewportPositionChange
イベントに以下のようなコードを書いたところ、近い動きになりました。
uses System.Math;
procedure TForm1.VertScrollBox1ViewportPositionChange(Sender: TObject;
const OldViewportPosition, NewViewportPosition: TPointF;
const ContentSizeChanged: Boolean);
begin
if ABS(VertScrollBox1.AniCalculations.CurrentVelocity.Y) < 100 then //スクロール速度が一定以下だったら
begin
if VertScrollBox1.ViewportPosition.Y < Panel1.Height * 0.5 then
begin
VertScrollBox1.AniCalculations.MouseWheel(0,-5); //マウスホイール操作を疑似発生する(上スクロール)
end
else if VertScrollBox1.ViewportPosition.Y >= Panel1.Height * 0.5 then
begin
VertScrollBox1.AniCalculations.MouseWheel(0,6); //下スクロール
end;
end;
end;
※マジックナンバー箇所は目分量で調整しました
※どの動作環境でも同じ速さでスクロールするかわかりません
わかり辛いのですが、こんな動きになります。(Android実機動作例)
##例2:入力欄をタップするとスクロールする(パンする)UI
Delphiで作成したスマートフォンアプリは、ソフトウェアキーボード表示の際に自動でパンしません。入力欄が隠れないようなUIデザインをまずは考える必要があります。
どうしても画面の下側にも入力欄を設けたい場合、入力欄の土台となるコントロールの高さを余分にとるか、画面下部にソフトウェアキーボードの高さ分のパネルを配置し、TVertScrollBoxでスクロールできるようにする、などの方法があります。
今回は後者をやってみます。
(TVertScrollBoxを使わずに、土台の位置を直接ずらすことも可能です)
Panel_VK(画面下部パネル)のHeightについては、スクリーン高さの4割ぐらいを設定しておきます。AlignはどちらもTopです。
ソフトウェアキーボードの高さはForm.OnVirtualKeyboardShown
イベントにて、引数のBoundsから取得できますが、簡略化のため、キーボードの高さがPanel_VKの高さを越えないものとして作成します。
起動時にパネルの高さを設定し、入力コントロールのOnEnterイベントにてViewportPositionの値を変更します。
procedure TForm1.FormCreate(Sender: TObject);
begin
Panel1.Height := ClientHeight;
Panel_VK.Height := ClientHeight * 0.4;
end;
procedure TForm1.EditEnter(Sender: TObject);
var
bottom:single;
overlapped:single;
begin
bottom := TControl(sender).Position.Y + TControl(sender).Height;
overlapped := Panel1.Height - Panel_VK.Height - bottom;
if overlapped < 0 then
VertScrollBox1.ViewportPosition := TPointF.Create(0,-overlapped);
end;
###なめらかスクロール
せっかくなのでアニメーションさせたい! しかしViewportPosition
はTPointF
型なのでFloatAnimation
が適用できません。困った・・。
と思っていたら作例がありました。 → TPointAnimation
このコードを拝借して、コンポーネント化して配置するとこのようになります。(参考:コンポーネントの新規作成)
(VertScrollBox1の子になるように配置してください)
EditEnterイベント内のコードを一部変更します。
if overlapped < 0 then
VertScrollBox1.ViewportPosition := TPointF.Create(0,-overlapped);
↓
if overlapped < 0 then
begin
PointAnimation1.StopValue := TPointF.Create(0,-overlapped);
PointAnimation1.Start;
end;
###OnVirtualKeyboardHiddenは使わないの?
当初はShown時にPanel_VKの高さを設定して、Hidden時にゼロに戻したらいいんや!と思ったのですが、環境によってはOnVirtualKeyboardHiddenイベントが発生しないとのことです(BlackberryKey2もだめでした!)。気をつけましょう!
#おわりに
取り留めのない記事になってしまいましたが、(Delphi未経験の方には)こんなこともできるんだな~ 程度に見てもらえれば幸いです。