「フォームアニメーションで満⾜度向上︕
モバイルアプリ改善術」
第32回 エンバカデロ・デベロッパーキャンプ

RAD Studio 勉強会 大阪
⽑利 春幸 (Haruyuki Mohri)

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

はじめに

モバイルアプリ制作でのユーザーからの要望を聞いていると、動きのある画面展開が必須になっています。作るだけで評価されていた時代とは違い、画面デザイン含めた動きの要望が数多くなったモバイル開発。
「エンドユーザーから⾒た商品⼒」を⾼めるためのテクニックが必要とされています。フォームをただShowしたりタブを配置するだけではない、こだわりのあるアプリを構築するためのDelphi/C++Builder固有のテクニックを、こうした要望を実現するために悪戦苦闘した経験をもとに解説します。

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

2

アジェンダ 画面切替について• 別画面切替時でのアニメーションについて

 影付け• TGlowEffect, TShadowEffectを使って雰囲気を出す

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

3

画⾯切替について
void __fastcall TForm1::Button1Click(TObject *Sender){
Form2->ShowModal();}Windowsアプリケーションでの画面切替の場合Show()などを使って切替を⾏っていた
同じようにiOSでビルド実⾏すると違和感ないでしょうか︖

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

4

今までの画⾯切替(iOSで実装した場合)
void __fastcall TForm1::Button1Click(TObject *Sender){
Form2->ShowModal();}

動作としては正常でプログラムとしても間違いはありません
機能としては満足している業務として使うのでこれで十分(ex1)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

5

Xcodeでの画⾯切替Interface Builder

標準で4つの画面切替時のアニメーションが選択できます

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

6

jQuery Mobileでの画⾯切替<div id="Form1" data-role="page"><div role="main" class="ui-content">
Form1<br /><a href="#Form2" data-role="button" data-transition="slide" direction="reverse">Button</a></div></div><div id="Form2" data-role="page"><div role="main" class="ui-content">
Form2<br /><a href="#Form1" data-role="button" data-transition="slideup" direction="reverse">Button</a></div></div>

data-transitionで設定します(slidedown, slideup, slide, slidefade, flow, turn, flip, pop, fade)

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

7

jQuery Mobileでの画⾯切替2
slidedown
slideupslide
slidefadeflow
turnflip
popfade本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

8

画⾯切替時にスライドアニメーション
Xcodeと jQuery Mobileを例としてあげましたが 画面切替時にアニメーションを使う事が当然のようになっていて、エンドユーザーからも同じような要望があります
画面切替時にアニメーションにする事で使う側の⼈に画面が切り替わった事を意識させているのでは︖
項目が似ている画面などはアニメーション切替を使う事は有効でした

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

9

画⾯切替でShowを減らすとユーザーは⾒やすい?
エンドユーザーは画面切替時アニメーションでスライドするのを他のアプリで⾒慣れている⾃⾝の画面切替時に対しての意識を変える事にしました。
(Form2.Showすればいいシーンと動きをつけないといけないシーンを分ける)
TFloatAnimationを 使って動きをつけていく

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

10

Delphi / C++BuilderでShow使わずに画⾯切替を⾏う
画面切替を⾏うにはたくさんの⽅法があり最終的に動けば全て正解だと思います
その中で、僕が⾏った⽅法をいくつかご紹介したいと思います

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

11

TTabControlで画⾯切替1
SetActiveTabWithTransition メソッドを使ったいちばんシンプルな⽅法です

下のタブボタンを見えなくすれば画面が切り替わったように思える(ex2)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

12

TTabControlで画⾯切替1.1
SlideReversed
TabItem3

TabItem2

TabItem1

SlideSlide(ex2)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

13

TTabControlで画⾯切替2
void __fastcall TForm1::Button1Click(TObject *Sender){
TabControl1->SetActiveTabWithTransition(TabItem2, TTabTransition::Slide, TTabTransitionDirection::Normal);}//--------------------------------------------------------------------------void __fastcall TForm1::Button2Click(TObject *Sender){
TabControl1->SetActiveTabWithTransition(TabItem3, TTabTransition::Slide, TTabTransitionDirection::Normal);}//--------------------------------------------------------------------------void __fastcall TForm1::Button3Click(TObject *Sender){
TabControl1->SetActiveTabWithTransition(TabItem1, TTabTransition::Slide,TTabTransitionDirection::Reversed);}

実装したのはこれだけです

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

14

TTabControlで画⾯切替3
enum class DECLSPEC_DENUM TTabTransition : unsigned char { None, Slide, ttNone_DEPRECATED_ATTRIBUTE3("Use TTabTransition.None") = 0x0, ttSlide _DEPRECATED_ATTRIBUTE3("UseTTabTransition.Slide") = 0x1 };TTabTransition = (None, Slide); //Delphi
TTabTransitionDirection = (Normal, Reversed);

TTabTransitionはスライドする/しないの２択なのですが今後増えれば嬉しいです

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

15

複数のパネルなどで画⾯切替1
TPanelや TLayout を使って画面切替

TPanelや Tlayout をTFloatAnimationを使って切替に⾒せかける(ex3)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

16

複数のパネルなどで画⾯切替1.1
Panel2

Form1

Panel2Slide

Panel1

Slide

Slide

Panel1(ex3)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

17

複数のパネルなどで画⾯切替2
void __fastcall TForm1::Button1Click(TObject *Sender){
FloatAnimation1->StartValue = Panel1->Position->Y;
FloatAnimation1->StopValue = 0;
FloatAnimation1->Start();}void __fastcall TForm1::Button2Click(TObject *Sender){
FloatAnimation2->StartValue = Panel2->Position->X;
FloatAnimation2->StopValue = 0;
FloatAnimation2->Start();}void __fastcall TForm1::Button3Click(TObject *Sender){
FloatAnimation1->StartValue = 0;
FloatAnimation1->StopValue = this->Height + 10;
FloatAnimation1->Start();FloatAnimation2->StartValue = 0;
FloatAnimation2->StopValue = this->Width + 10;
FloatAnimation2->Start();}
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

コードはこれだけです18

TMultiViewで画⾯切替1
TMultiViewコンポーネントを使っても同じように画面の切り替えできます
Modeプロパティをうまく使えば簡単に別Formのような扱いのできる画面が作れますenum class DECLSPEC_DENUM TMultiViewMode : unsigned char { PlatformBehaviour, Panel, Popover, Drawer,Custom, NavigationPane };PlatformBehaviour, Panel, Popover, Drawer, Custom, NavigationPane 6つモードがあります(ex5)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

19

TMultiViewで画⾯切替2
PlatformBehaviour, Panel, Popover, Drawer, Custom, NavigationPane
モード表示

Drawerドローワ（プッシュ/オーバーラップ）

Panel

ドッキングされたパネル

PlatformBehaviour

プラットフォーム依存の動作

Popover

ポップアップ メニュー

NavigationPane

ナビゲーション ペイン

Customカスタム

Popover, Drawer, NavigationPaneは動きがある別画面を作れます

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

20

TMultiViewで画⾯切替3
PlatformBehaviour, Panel, Popover, Drawer, Custom, NavigationPane
Mode = PlatformBehaviourの場合
デバイスの種類

デバイスの向き

マスタ ペインの表示

スマートフォン

横、縦Drawer（プッシュ/オーバーラップ）

タブレット

横

ドッキングされたPanel

タブレット縦Drawer（プッシュ/オーバーラップ）

Windows 10
Windows 8以前
OS X

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

NavigationPane(ナビゲーションペイン)
ドッキングされたPanel21

TMultiViewで画⾯切替2.1
TMultiViewMode::Drawer を使って画面切替
iPhoneの場合、this->ClientWidth=320なのでMultiView1 Width=320にする

void __fastcall TForm1::MultiView1Shown(TObject *Sender){
MultiView1->MasterButton = Button2;}//--------------------------------------------------------------------------void __fastcall TForm1::MultiView1StartHiding(TObject *Sender){MultiView1->MasterButton = Button1;}(ex5)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

22

TMultiViewで画⾯切替2.2
TMultiViewMode::Drawer を使って画面切替

Slidevoid __fastcall TForm1::MultiView1Shown(TObject *Sender){
MultiView1->MasterButton = Button2;}

Slide

Slide
void __fastcall TForm1::MultiView1StartHiding(TObject *Sender){
MultiView1->MasterButton = Button1;}
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

23

TMultiViewで画⾯切替3
PlatformBehaviour, Panel, Popover, Drawer, Custom, NavigationPane

TSplitViewAppearance
TDrawerAppearanceTNavigationPaneAppearance

TPopoverAppearance
TShadowAppearance

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

24

設計上フォームを分割したい1
Form1, Form2を使ってスライドさせたい場合

Form2の部品をレイアウトに貼ればOK(ex6)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

25

設計上フォームを分割したい2
Form1, Form2を使ってスライドさせたい場合
extern "C" int FMXmain(){try{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);//
Application->CreateForm(__classid(TForm2), &Form2);
Application->Run();
}
．．．

(ex6)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

26

設計上フォームを分割したい3
MultiView1->MasterButton = Button1;なのでvoid __fastcall TForm1::MultiView1StartShowing(TObject *Sender){
MultiView1->MasterButton = Button1;
if (Form2 == nullptr ){Form2 = new TForm2(this);}
Layout1->AddObject(Form2->Panel1);
Form2->Panel1->Align = TAlignLayout::Client;
MultiView1->MasterButton = Form2->Button1;}．．

Layout1->AddObjectに入れればForm2をスライドしたように⾒える(ex6)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

27

設計上フォームを分割したい4
MultiView1->MasterButton = Button1;なのでvoid __fastcall TForm1::MultiView1StartShowing(TObject *Sender){
MultiView1->MasterButton = Button1;
Form2 = new TForm2(this);
Layout1->AddObject(Form2->Panel1);
Form2->Panel1->Align = TAlignLayout::Client;}．．

Layout1->AddObjectに入れればForm2をスライドしたように⾒える(ex6)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

28

設計上フォームを分割したいフレーム編1
Form1
Frame2(Delphi)(ex7)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

29

設計上フォームを分割したいフレーム編2
void __fastcall TForm1::MultiView1StartShowing(TObject *Sender){if (Frame2 == nullptr) {Frame2 = new TFrame2(this);}
MultiView1->AddObject(Frame2);
Frame2->Align = TAlignLayout::Client;
MultiView1->MasterButton = Frame2->Button1;}//--------------------------------------------------------------------------void __fastcall TForm1::MultiView1StartHiding(TObject *Sender){
MultiView1->MasterButton = Button1;}(ex7)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

30

設計上フォームを分割したいフレーム編3
Frameを使った場合 設計画面がWindowsデザインのままです
実⾏するとiOSのスタイルで表示されます(ex7)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

31

影1
最近のスマホ画面フラットデザインが多いのであまり気にしなくてもよくなりました。
しかし、影で奥⾏きをつけて欲しいと⾔われる事もあります

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

32

影2
例えばウィンドウズなら何気なくパネルTopに貼り
TMemo Align = TAlignLayout::Client(ex4)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

33

影3
このままiOSでビルドするとフラットデザインなので問題ないがパネルとTMemoの境目が⾒づらい同色パネルが2つある場合も同じ
ここにエフェクトを使って奥⾏きを出す

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

34

影4
このままiOSでビルドするとTPanelにTGlowEffect貼った。
反映されていない(ex4)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

35

影5
FMXは*.fmx上から順番に描画している
object Form1: TForm1
object Panel1: TPanelobject Edit1: TEdit
endobject Button1: TButtonend
object GlowEffect1: TGlowEffectSoftness = 0.400000005960464400
GlowColor = claBlack
Opacity = 0.899999976158142100
end
end
object Memo1: TMemo
endend

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

↓パネルを書いて↓エフェクトを書いて↓メモを書いている36

影6
FMXは*.fmx上から順番に描画している
object Form1: TForm1
object Memo1: TMemo
endobject Panel1: TPanelobject Edit1: TEdit
endobject Button1: TButtonend
object GlowEffect1: TGlowEffectSoftness = 0.400000005960464400
GlowColor = claBlack
Opacity = 0.899999976158142100
end
end
end

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

↓メモを書いている↓パネルを書いて↓エフェクトを書く

これでパネルが全面に移動される

37

影7
エディタでfmxファイルを変更するとモジュール ‘Unit1.cpp' のタイムスタンプが変更されました。
読みなおしますか︖[はい(Y)] [いいえ(N)](ex4)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

38

影8
エディタでfmxファイルを読み直すとTGlowEffect を貼った影が出ます(ex4)
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

39

影9
エディタでfmxファイルの書き換え面倒です
http://ht-deko.com/junkbox.html#DFMCONVEXP
ここに 簡単にfmxを入れ替えるChangeCreateOrderツールがあります

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

40

影10 ChangeCreateOrder
ChangeCreateOrder.exe 画面

ドラッグ＆ドロップで任意の位置へ移動する事ができます

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

41

IBLiteInterBase XE7 のデータベースファイルがそのまま利⽤可能ですInterBase XE7をLinuxにインストールしてデータを作成したファイルをiOSで使いたいと思います

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

42

InterBase_XE7_JPインストール
InterBase_XE7_JP インストール
InterBase_XE7_JP/Disk1/InstData/Linux/VM この中に
ib64_install.bin ib_install.binがあります
コマンドラインインストールの場合は次のように実⾏します
sudo ./ib64_install.bin -i console

これでインストールが開始されまます
インストール時に幾つかの質問で止まるのでyes

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

43

InterBase_XE7_JPライセンス登録/opt/interbase/binにインストールされたプログラムが入りますsudo ./LicenseManagerLauncher -i Console

ここで InterBase XE7 Server エディション、または InterBase XE7 Developer エディションのライセンスを入れるとInterbase XE7が使えます

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

44

InterBase_XE7_JP テーブル作成
isqlで テーブルを作成できます./isql
SQL> CREATE DATABASE '/home/***/DBファイル名.ib';
SQL>
SQL> quit; --quitで抜けます

DBファイルがある場合./isql
SQL> connect '/home/****/DBファイル名.ib';

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

45

IBLite をiOSで動かしてみる
先ほどLinuxにInterBase_XE7_JPをインストールしてCreate DBしたファイルを使います./isql
SQL> CREATE DATABASE ‘/home/***/a1234.ib';-rw---S--- 1 root root 925696 5月 30 15:03 a1234.ib↑925KByteほどのファイルでできます
作成したDBファイル(a1234.ib)をRAD Studioインストールしている環境にコピーします

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

46

IBLite をiOSで動かしてみる1iOS プロジェクトを新規作成して 配置の設定
配置一覧から「機能ファイルの追加」[InterBase ToGo][iOSDevice] を選択
配置一覧から「ファイルの追加」

InterBaseで作成したDBファイルを追加する「StartUp¥Documents¥」ここ本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

47

IBLite をiOSで動かしてみる2
TBL_TEST1と⾔うテーブルを作成します CREATE TABLE TBL_TEST1(c1 int, c2 varchar(100) );void __fastcall TForm1::Button1Click(TObject *Sender){using TPath_Ioutils = System::Ioutils::TPath;
TFileName stDBName = TPath_Ioutils::Combine(TPath_Ioutils::TPath::GetDocumentsPath(), "a1234.ib");
if (FileExists(stDBName) ){FDConnection1->Params->Database = stDBName;
FDConnection1->Connected = True;
FDQuery1->SQL->Text = L"CREATE TABLE TBL_TEST1(c1 int, c2 varchar(100) );";
FDQuery1->ExecSQL();
FDConnection1->Connected = False;}}

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

48

IBLite をiOSで動かしてみる3
TBL_TEST1テーブルインサート
void __fastcall TForm1::Button2Click(TObject *Sender){if (FileExists(stDBName) ){TDateTime dtTemp = Now();
FDConnection1->Params->Database = stDBName;
FDConnection1->Connected = True;for (int i = 0; i < 100; i++){
FDQuery1->SQL->Text = "INSERT INTO TBL_TEST1 values (" +IntToStr(i)+ ", '" + Edit1->Text +"') ";FDQuery1->ExecSQL();}
FDConnection1->Connected = False;
dtTemp = Now() - dtTemp;
Memo1->Lines->Append(L"Time " + FormatDateTime("hh:nn:ss", dtTemp));}}

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

49

IBLite をiOSで動かしてみる4
TBL_TEST1テーブル参照
void __fastcall TForm1::Button3Click(TObject *Sender){if (FileExists(stDBName) ){TDateTime dtTemp = Now();
FDConnection1->Params->Database = stDBName;
FDConnection1->Connected = True;
FDQuery1->SQL->Text = "select * from TBL_TEST1";
FDQuery1->Active = True;
while (!(FDQuery1->Eof)){Memo1->Lines->Append(
FDQuery1->FieldByName("c2")->AsWideString);
FDQuery1->Next();}
FDQuery1->Active = False;
FDConnection1->Connected = False;
dtTemp = Now() - dtTemp;
Memo1->Lines->Append(L"Time " + FormatDateTime("hh:nn:ss", dtTemp));}}
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

50

まとめ 画面切替• 画面切替時なぜ動きが必要かは利⽤者に切り替った事をお知らせする大事な役割• 様々な⽅法で動きのある画面遷移が作れる

 影付け• 雰囲気を出すのと利⽤者側から⾒て境界線メリハリが認識できる• *.fmxファイルの順番は重要

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

51

THANKS!
www.embarcadero.com/jp
第32回 エンバカデロ・デベロッパーキャンプ

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

52