NativeScriptのGetting Startedを試してみる(2


前回に続いてAndroid, iOS, Windows Phoneのアプリをjavascriptで書けるNativeScriptのGetting Startedを試していきます。サンプル画面が表示できたところからです。プロジェクトは以下のようになっています。

└── hello-world
    ├── app
    │   ├── app
    │   │   ├── app.css
    │   │   ├── app.js
    │   │   ├── bootstrap.js
    │   │   ├── main-page.js
    │   │   └── main-page.xml
    │   ├── App_Resources
    │   │   └── ...
    │   └── tns_modules
    │       └── ...
    └── platforms
        └── ...
  • app 以下が我々の開発スペースである。
  • platforms は初期状態では空。platform add すると追加される。ビルド用のリソースが格納される。このディレクトリは変更してはならない。
  • app/App_Resourcesはプラットフォームによって異なる個別のリソースを格納する。アイコンやスプラッシュシートなどが含まれる。
  • app/tns_modules にはNativeScriptモジュールが格納される。カメラやロケーションなどのプラットフォームの機能を提供する。
  • app/app/app.jsがアプリの開始点になる。サンプルではmain-pageをmainModuleに設定している。これはmain-page.jsとmain-page.xmlにコントロールを渡している。

Build Something Awesome

タスクマネージャを作成します。

目的は以下を理解することです。

  • UIの構築方法
  • MVVMの実装方法
  • CSSによるスタイリングの仕方

1. Add user interface

NativeScriptではUIの定義にXMLを用います。いまはapp/main-page.xmlの1ページのみです。同じディレクトリにtasks.xmlを作成しましょう。

app/tasks.xml
<Page loaded="onPageLoaded">
    <GridLayout rows="auto, *">
        <StackLayout orientation="horizontal" row="0">
            <TextField width="200" text="{{ task }}" hint="Enter a task" id="task" />
            <Button text="Add" tap="add"></Button>
        </StackLayout>

        <ListView items="{{ tasks }}" row="1">
            <ListView.itemTemplate>
                <Label text="{{ name }}" />
            </ListView.itemTemplate>
        </ListView>
    </GridLayout>
</Page>

ここでNativeScriptのレイアウトメカニズムが登場します。GridLayout と StackLayoutです。ここではGridLayoutで画面を上下に2分しています。
StackLayoutは名前の通り、縦か横にものを積むレイアウトです。例では横向きにテキスト欄とボタンを並べています。
そのほかのレイアウトについては http://docs.nativescript.org/layouts.html を参照ください。
だいたい察しがついていると思いますが、XML内の"{{ name }}"などはデータバインディングです。どのように働くかは次項で確認します。

2. Create the view model

NativeScriptのフレームワークはMVVMパターンに従って最適化されています。これはデータとUIを同期させるエレガントな手法だそうです。app/tasks.jsファイルを作り、その働きを見てみましょう。

app/tasks.js
var observableModule = require("data/observable");
var observableArray = require("data/observable-array");
var viewModule = require("ui/core/view");

var tasks = new observableArray.ObservableArray([]);
var pageData = new observableModule.Observable();
var page;

exports.onPageLoaded = function(args) {
    page = args.object;
    pageData.set("task", "");
    pageData.set("tasks", tasks);
    page.bindingContext = pageData;
};

exports.add = function() {
    tasks.push({ name: pageData.get("task") });
    pageData.set("task", "");
    viewModule.getViewById( page, "task" ).dismissSoftInput();
};

exportsがあるのでわかると思いますが、Node.jsのモジュールとしてjsファイルを作成してます。この例ではonPageLoaded と add の2つのメソッドが定義されており、それらはviewのxmlに渡されます。xmlを見るとPageとButtonタグでそれぞれが呼び出されているのがわかると思います。

次に重要なのがonPageLoaded内にあるpage.bindingContext = pageDataです。これはバインディング用のオブジェクトとしてpageDataを設定しています。これによりview側で{{ }}を使用してpageDataのプロパティにアクセスすることができます。たとえばpageDataのtasksにアクセスするなら{{tasks}}でアクセスできます。

MVVMアプローチの最大の利点は、データの変更に応じてビューが更新される点です。addメソッド内でtasksにタスクが追加されています。tasksはObservableであり、viewのListViewにバインドされているため、addメソッドが実行されると自動的にListViewの表示が更新されます。

これによりコードが簡潔になり、ロジックとビューが疎結合になります。この例だとjsはバインディングされるviewを気にする必要がありません。

3. Style your app

ではCSSを使って見た目をよくしましょう。
xmlと同名のCSSが自動的にロードされます。
またapp.cssは全ページに適応されます。少しタスクマネージャにスペースを設けるために、app.cssを以下のように変更しましょう。

app/app.css
label {
    margin: 15;
}
textfield {
    margin: 15;
}

4. The finishing touches

ではタスクマネージャをアプリの開始点に設定し、アプリを起動しましょう。エラーが出る場合はファイル名が間違ってる可能性が高いです。見直しましょう。

app/app.js
var application = require("application");
application.mainModule = "app/tasks";
application.start();
起動.
tns run android --emulator

うまくいけば以下のようなアプリが起動します。
原文のほうにGIFもあります。

Move Beyond the Basics

以上でGetting Startedは終了になります。なかなか便利そうですね。