LoginSignup
3
3

More than 5 years have passed since last update.

iOS/Android両対応時でNavigationWindowを使いつつAlloy Data Bindingも使う(Jade版とxp.ui)

Posted at

Titanium/Alloyでマルチプラットフォーム向けにアプリを作る際、以下のような問題があります。

Windowの中身を二度書くのがいやなのと、中身を共通化してrequireしようとするとdataCollectionがちゃんと動かないんですよねえ。

- Titanium - NavigationWindowでもAlloyのCollectionを使いたいしAndroidとコードを共有したい - Qiita

iPhoneでナビゲーションバーを使うにはNavigationWindowが必要ですが、Androidにはないコンポーネントなので、ビューを作るのに一工夫必要になってしまうのですが、そうするとデータバインディングと相性が悪いらしいという悩ましい問題です。

上の記事では、コントローラ内でiOSかAndroidを判断して、Androidの場合はWindowをそのまま使い、iOSの場合はNavigationWindowを生成してWindowを挿入するような形で対応する方法を紹介されていました。

正攻法で行くなら、冗長になってしまいますが、上記記事のコメントにあるようにiOSとAndroidそれぞれにWindowを書く形、

<Alloy>
  <Collection src="entry" />
  <NavigatonWindow platfrom="ios">
  </NavigationWindow>
  <Window platfrom="android">
  </Window>
</Alloy>

もしくは app/views/ 以下にプラットフォームごとのフォルダを用意して、それぞれのViewを実装する形でしょうか。

データバインディングを使わないのであれば、 require を使ってわかりやすく共通化できるのですが。

参考: iOSとAndroidのナビゲーションサンプル | garicchi.com

そこで、別のアプローチとして、私が普段Titanium開発をする際に使っているViewをJadeで書く(&TSSをStylusで書く)方式での解決方法を紹介したいと思います。

参考: Titanium Alloy with StylusでFontを設定 - Umi Uyuraのブログ

XP.UI.js(Jadeを使わない方法)

と言いつつ、先にJadeを使わない場合の解決のひとつを紹介。

Titanium/Alloy向けの便利 FokkeZB/UTiL に含まれている xp.ui.js を使う方法です。

詳細は リポジトリのドキュメント に詳しく書かれていますが、iOS以外のプラットフォーム用にダミーのNavigationWindowを提供しているので、以下のように module="xp.ui" を設定することで、iOS/Android両方に対応できます。

<Alloy>
  <NavigationWindow module="xp.ui">
    <Window>
      <Label>Hello World</Label>
    </Window>
  </NavigationWindow>
</Alloy>

先日Alloy Modelの勉強していたときに使ってみたので、データバインディングと組み合わせも問題なさそうです。

Alloy Modelの学習 - Umi Uyuraのブログ

Jade版

Jadeでviewを拡張する方法としては、 include extend mixin などがありますが、このうち mixin を使うことにしました。

Mixins - Jade

mixin は、再利用可能なコードブロックを作って、任意の箇所で何度も生成できる機能です。関数のように引数を取ることもできます。

それを利用して、まずは mixin で基本となる画面をWindowベースで作りました。引数でプラットフォームの指定を受け取るようにしたので、生成される <Window> タグは各プラットフォーム専用になります。

それを、iOS用のNavigationWindow以下と、Android用にAlloyタグ配下の2箇所で呼び出すようにしました。

app/views/index.jade

mixin mainWindow(platform)
  Window.container(platform=platform, title="Alloy Project Demo", onOpen="doOpen", onClose="doClose")
    ListView(onItemclick="clickItem")
      ListSection(dataCollection="member")
        ListItem(title="{name}", itemId="{id}")/

Alloy
  Collection(src="member")/
  NavigationWindow(platform="ios")
    +mainWindow("ios")
  +mainWindow("android")

これをJadeコンパイルすると、以下のようなView XMLが生成されます。

app/views/index.xml

<Alloy>
  <Collection src="member"/>
  <NavigationWindow platform="ios">
    <Window platform="ios" title="Alloy Project Demo" onOpen="doOpen" onClose="doClose" class="container">
      <ListView onItemclick="clickItem">
        <ListSection dataCollection="member">
          <ListItem title="{name}" itemId="{id}"/>
        </ListSection>
      </ListView>
    </Window>
  </NavigationWindow>
  <Window platform="android" title="Alloy Project Demo" onOpen="doOpen" onClose="doClose" class="container">
    <ListView onItemclick="clickItem">
      <ListSection dataCollection="member">
        <ListItem title="{name}" itemId="{id}"/>
      </ListSection>
    </ListView>
  </Window>
</Alloy>

冒頭に正攻法として紹介した、iOSとAndroidそれぞれに向けて二重にWindow以下を書いた形で出力されました。当然データバインディングも問題なく動きます。

まとめ

Jadeを使うことで、Windowの中身を1箇所で書くことができ、煩雑さは多少減らせるのではないかな、と思います。

Jade版でのサンプルをGitHubにあげてあります。

umi-uyura/AlloyModelWithJadeNavWin

ちなみに、サンプルはJadeおよびStylusから生成したView XMLとTSSも含んでいるので、Jade & Stylusがない環境の人でも、alloy.jmkを削除して (appc) ti build を実行してもらえば動きます。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3