さて、今回から、実際にUXマークアップを書きながら、それがどんなアプリになるのかを書いていきたいと思います。とはいっても、自分もまだ初心者なので、まずは公式サイトのチュートリアルに沿って進めていきます。
今回のページはこちら
###イントロ
複数回のチュートリアルで作るアプリはハイキング情報を表示したり、編集したりするアプリです。情報を表示するビジュアルを表すビューと編集可能なビジュアルを表すビューのふたつから構成されます。
チュートリアルの最終形はこちらにアップされています。
今回はこちらのページを参考に進めていきます。
・プロジェクトを作成して、プレビューする
・Observerを追加してみる
・viewとview modelを分離してみる
では早速始めましょう!
###プロジェクトを作る
前にも一度説明した気がしますが、まずはプロジェクトをつくります。
$ fuse create app tutorial01
実行すると下記のような構成になります。
$ ls
MainView.ux tutorial01.unoproj
このふたつのファイルが最低限必要なファイルになります。
.unoprojにはいろいろなプロジェクトの設定を、MainView.uxには、アプリのビューを記述していきます。今回はこのMainView.uxをいじっていきます。
###最初のハイキングを表示しよう
プロジェクトを作ったら、データの表示をやってみましょう。まず、MainView.uxを開きます。
<App>
</App>
空の<App>
がすでに挿入されているはずです。注意したいのが、UXマークアップでは、大文字と小文字を区別しますので、<app>
と書かないようにしましょう。
さて、単純なテキストを追加してみます。
<App>
<Text>Tricky Trails</Text>
</App>
保存すると、すぐにプレビューにその変更が反映されていると思います。
Fuseではタイポや誤植があると、プレビューが実行されません。なので、こまめに保存して、間違っている箇所がどこなのかを細かく確認するとよいでしょう。
先ほどのテキストはローカルのシミュレータで確認すると問題ないですが、デバイスのステータスバーに少しかぶることがあります。これを防ぐために、ClientPanel
を追加します。
<App>
<ClientPanel>
<Text>Tricky Trails</Text>
</ClientPanel>
</App>
ClientPanel
は画面の上部と下部に、OS特有の領域を確保するためのコンテナです。デフォルトで入れておくといいと思います。
続いて、StackPanel
を追加します。StackPanel
は、含まれる子要素を垂直、または水平に並べるためのコンテナです。含まれる子要素が一つの場合はとくに変化がありませんが、これから要素を追加していくので、あらかじめ入れておきます。
<App>
<ClientPanel>
<StackPanel>
<Text>Tricky Trails</Text>
</StackPanel>
</ClientPanel>
</App>
これで準備はバッチリです!
###ビューモデルとデータバインディング
さて、テキストが表示されたところまではいいですが、完全にハードコーディングになってしまっています。ハイキングの情報は編集したいので、表示するテキストの内容は分離させたいところです。そこでJavaScriptの登場です!
ハイキングの名前をエクスポートするJSを追加してみましょう。
<App>
<ClientPanel>
<JavaScript>
var _name = "Tricky Trails";
module.exports = {
name: _name
};
</JavaScript>
<StackPanel>
<Text Value="{name}" />
</StackPanel>
</ClientPanel>
</App>
非常に簡単ですね!<JavaScript>
を追加して、UXマークアップで使いたい値をmodule.exports
するだけで、あとは{key}
で参照できます。ただ、まだJS -> UXマークアップの一方通行なので、今度は編集できるようにしてみましょう。
###Observablesを追加して、Two-Wayバインディングを実現する
まずは入力用のTextBoxを追加する必要があります。Textboxは基本的なスタイリングがされている1行の入力フィールドです。今回は名前を編集するのに使います。しかし、追加する前に、このTextboxが編集されたらその内容を他のUIに通知する仕組みを先に作りましょう。具体的にはFuseが用意しているObservableを追加して、名前の変数の状態を監視します。Observableを使用するにはまずインポートする必要があります。
var Observable = require("FuseJS/Observable");
そして、このObservableに名前の変数を監視させるよう設定します。
var name = Observable("Tricky Trails");
変数nameに、テキストをそのまま入れる代わりに、Observableを代入します。これだけで、変更を監視し、その変更をUIに伝えるところまで、必要な処理を組んでくれます。
では実際にTextboxを追加して、変更してみましょう!
<App>
<ClientPanel>
<JavaScript>
var Observable = require("FuseJS/Observable")
var _name = Observable("Tricky Trails");
module.exports = {
name: _name
};
</JavaScript>
<StackPanel>
<Text Value="{name}" />
<TextBox Value="{name}" />
</StackPanel>
</ClientPanel>
</App>
プレビューを見てみると、Observableに設定されたテキストがただのテキストと、入力用のテキストボックスに指定されているのがわかります。そして、下のテキストボックスを編集すると、上のテキストの方にも反映されます。これはTextboxのValueプロパティが双方向データバインディングを提供しているからです。
上のテキストはキャプションに使いたいと思います。また、名前の他にも、フィールドも追加しておきます。
var _name = Observable("Tricky Trails");
var _location = Observable("Lakebed, Utah");
var _distance = Observable(10.4);
var _rating = Observable(4);
var _comments = Observable("This hike was nice and hike-like. Glad I didn't bring a bike.");
module.exports = {
name: _name,
location: _location,
distance: _distance,
rating: _rating,
comments: _comments
};
UIの方も同じく追加します。
<Text>Name:</Text>
<TextBox Value="{name}" />
<Text>Location:</Text>
<TextBox Value="{location}" />
<Text>Distance (km):</Text>
<TextBox Value="{distance}" InputHint="Decimal" />
<Text>Rating:</Text>
<TextBox Value="{rating}" InputHint="Integer" />
<Text>Comments:</Text>
<TextBox Value="{comments}" />
よりユーザビリティをあげるために、InputHint
を追加しています。これはHTMLのinputでいうtypeみたいなもので、それぞれのOSで適切なキーボードを表示するように設定できます。
###仕上げ
いくつか最後の仕上げをします。上の画像のコメントの欄を見てみてください。途中で文章が見えなくなっているのがわかります。これではわかりづらいので、複数行になるようにしてみましょう。
<Text>Comments:</Text>
<TextView Value="{comments}" TextWrapping="Wrap" />
TextBox
ではなく、TextView
を使い、TextWrapping="Wrap"
を指定します。そうすると、テキストを全て表示するように折り返してくれます。
しかし、今度はコメントがめちゃくちゃ長いと、画面外に出てしまって、見えなくなってしまいます。そこで今度はScrollView
を使います。
<ScrollView>
<StackPanel>
<Text>Name:</Text>
<TextBox Value="{name}" />
<Text>Location:</Text>
<TextBox Value="{location}" />
<Text>Distance (km):</Text>
<TextBox Value="{distance}" InputHint="Decimal" />
<Text>Rating:</Text>
<TextBox Value="{rating}" InputHint="Integer" />
<Text>Comments:</Text>
<TextView Value="{comments}" TextWrapping="Wrap" />
</StackPanel>
</ScrollView>
これで、画面全体を上下にスクロールできるようになりました。このチュートリアルの成果物は下記です。
コード全体は下記です。
<App>
<ClientPanel>
<JavaScript>
var Observable = require("FuseJS/Observable")
var _name = Observable("Tricky Trails");
var _location = Observable("Lakebed, Utah");
var _distance = Observable(10.4);
var _rating = Observable(4);
var _comments = Observable("This hike was nice and hike-like. Glad I didn't bring a bike.");
module.exports = {
name: _name,
location: _location,
distance: _distance,
rating: _rating,
comments: _comments
};
</JavaScript>
<ScrollView>
<StackPanel>
<Text>Name:</Text>
<TextBox Value="{name}" />
<Text>Location:</Text>
<TextBox Value="{location}" />
<Text>Distance (km):</Text>
<TextBox Value="{distance}" InputHint="Decimal" />
<Text>Rating:</Text>
<TextBox Value="{rating}" InputHint="Integer" />
<Text>Comments:</Text>
<TextView Value="{comments}" TextWrapping="Wrap" />
</StackPanel>
</ScrollView>
</ClientPanel>
</App>
###今回登場したFuseの機能たち
###明日の内容
明日はこちらの内容に沿って進めます。今回は一つのハイキングに関する情報でしたが、複数のハイキングを作ってみましょう。