読者です 読者をやめる 読者になる 読者になる

TitaniumMobile勉強記

Web系エンジニア向けのキャリアアドバイザーやってましたが現在はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連(Node.js、Titanium)あたり

Alloyに自作ライブラリを組み込んで利用する方法

Titanium Mobile

スライドメニューの実装が出来たので、Alloyでもう少しアプリっぽいものを作ろうと考えてる人の参考になりそうなものを考えてみました。

本来なら、Alloy標準機能のModelの機能を紹介したい所なのですが、まだそっちはあまり本格的にいじれてないのと、外部のライブラリを手軽に使う方法をたまたま公式ドキュメントを見てて知ったので今回はそれについて紹介することにします。

  • 目次
    • CommonJSスタイルのライブラリは、app/lib配下に置けば手軽に利用できる
    • まずはベースとなるUIを考える
    • NHK番組表APIにアクセスする
      • 「本日の番組」という項目を得るために、$.subMenuにイベントリスナーを設定
      • NHK番組表APIのライブラリ利用の準備
      • 本日の番組がクリックされた時に実際にNHK番組表APIにアクセスして情報更新する
      • 最終的な形
      • Alloyの流儀に従ってUI要素の処理をStylesにうつす
        • styles/index.tssの修正
        • controllers/index.coffeeの修正
    • まとめ

CommonJSスタイルのライブラリは、app/lib配下に置けば手軽に利用できる

どういうことかというAlloyのappディレクトリ配下にlibというフォルダを作成して、組み込みたいCommonJSのライブラリを配置すればOKです

私が作ったNHK番組表APIにアクセスするファイルをGitHubにアップしてあるのですが、TitaniumのClassicの環境で利用することを想定して、別途Moment.jsとかUnderscore.jsの読み込みを工夫してある実装になってます。 Alloyは標準でMoment.jsとかUnderscore.jsが使えるので、少しだけ手直ししたやつをGistに貼ったのでこれをダウンロードをダウンロードして、libフォルダ配下に配置します。

最終的にこのようになればOKです

.
├── README
├── alloy.jmk
├── alloy.js
├── assets
│   ├── android
│   ├── blackberry
│   ├── iphone
│   ├── mobileweb
│   └── tizen
├── config.json
├── controllers
│   └── index.coffee
├── lib/
│   └── nhk.js
├── models/
├── styles/
│   └── index.tss
├── views/
│   ├── index.xml
│   └── index.jade
└── widgets/

ライブラリの配置が完了したので、実際にサンプルとなるアプリケーションを作っていきます。

まずはベースとなるUIを考える

ライブラリを利用する前に、まずは controller,view,styleの定義を行います。

前回作ったスライドメニューを流用してひとまずこのようなUIにしました。

f:id:h5y1m141:20140418071150p:plain

f:id:h5y1m141:20140418071157p:plain

ソースコード

上記実現するソースコードを以下しめします

index.jade

Alloy
  TabGroup
    Tab#tabOne
      Window#mainWindow.container(title="main")
        LeftNavButton(platform="ios")
          Button#showBtn(title="MENU")

        TableView#mainMenu
        TableView#subMenu
          TableViewRow.row(title="本日の番組")
          TableViewRow.row(title="昨日の番組")
          TableViewRow.row(title="エリアを選択する")

index.coffee

$.index.open()
$.showBtn.addEventListener 'click', (e) ->
  slide()
  
slide = (e) ->
  if $.mainMenu.slideState is false
    leftPosition = 200
    $.mainMenu.slideState = true
  else
    leftPosition = 0
    $.mainMenu.slideState = false
  
  transform = Titanium.UI.create2DMatrix()
  animation = Titanium.UI.createAnimation()
  animation.left = leftPosition
  animation.transform = transform
  animation.duration = 300
  
  $.mainMenu.animate(animation)

index.tss

".container": {
    backgroundColor:"#f9f9f9"
},

"#mainWindow":{
    statusBarStyle:0,
    tabBarHidden:true,
    slideState:false,
    backgroundColor:"#f9f9f9"
}
"#mainMenu":{
    width:Ti.UI.FULL,
    height:Ti.UI.FULL,
    backgroundColor:"#eeeeee",
    separatorColor:"#ededed",
    top:0,
    left:0,
    zIndex:2,
    slideState:false

}
"#subMenu":{
    width:200,
    height:Ti.UI.FULL,
    backgroundColor:"#cccccc",
    separatorColor:"#cdcdcd",
    top:0,
    left:0,
    zIndex:1
}

".row":{
    backgroundColor:"#cccccc",
    width:Ti.UI.FULL,
    height:40
}

ベースとなるUIが出来たので、これ以降でlib配下のライブラリを読み込んで実際にNHK番組表APIにアクセスする手順を解説します

NHK番組表APIにアクセスする

Menuボタンをタッチすると、いくつか項目が表示されてその中の「本日の番組」という項目がクリックされた時に番組表情報を取得することを念頭に実装をしていきます

基本的にはControlの修正がメインになってきます

「本日の番組」という項目を得るために、$.subMenuにイベントリスナーを設定

$.subMenuはTableViewとして定義しておりe.indexの値をチェックすることで何番目の項目がクリックされたかわかります。

「本日の番組」は一番先頭なので、「0」になるため controllers/index.coffee に以下のように記述します

$.subMenu.addEventListener 'click', (e) ->
  if e.index is 0
    Ti.API.info "本日の番組情報を取得します"

というような形になります

NHK番組表APIのライブラリ利用の準備

nhk.jsはMoment.jsに依存してるため、Alloy標準で組み込まれてるMoment.jsを利用するための宣言を最初に行いつつ、ライブラリの読み込み、初期化処理をするためcontrollers/index.coffee に以下のように記述します。

moment = require('alloy/moment')
NHKProgram = require("nhk")
config =
  apikey:"YOUR API KEY"
client = new NHKProgram(config)
area = '東京'
service = "NHK総合1"

本日の番組がクリックされた時に実際にNHK番組表APIにアクセスして情報更新する

私が作ったライブラリは

client.list("エリア名", "サービス名","日付",callback関数)

という感じで利用します。

具体的には

$.subMenu.addEventListener 'click', (e) ->
  if e.index is 0
    Ti.API.info "本日の番組情報を取得します"
    todayDate = moment()
    client.list area,service,todayDate,(result) ->
    
    # result.list.g1 の配列に番組に関する情報が格納されているため
    # for program in result.list.g1 のようにして
    # 必要な情報を得る

という感じになります。

最終的な形

controllers/index.coffeeは最終的にはこのようになります。

moment = require('alloy/moment')

NHKProgram = require("nhk")
config =
  apikey:"YOUR API KEY"
client = new NHKProgram(config)
area = '東京'
service = "NHK総合1"

$.showBtn.addEventListener 'click', (e) ->
  slide()

$.subMenu.addEventListener 'click', (e) ->
  if e.index is 0
    todayDate = moment()
    client.list area,service,todayDate,(result) ->
      rows = [] 
      for program in result.list.g1
        row = Ti.UI.createTableViewRow
          width:Ti.UI.FULL
          height:80
          backgroundColor:"f3f3f3"
          programID:program.id
          
        title = Ti.UI.createLabel
          width:220
          height:50
          top:5
          left:70
          textAlign:'left'
          color:"#222"
          font:
            fontSize:14
            fontWeight:'bold'
          text:"#{program.title}"
            
        subtitle = Ti.UI.createLabel
          width:220
          height:20
          top:55
          left:70
          textAlign:'left'
          color:"#999"
          font:
            fontSize:12
          text:"#{program.subtitle}"
          
        timeTable = Ti.UI.createLabel
          width:60
          height:20
          top:20
          left:5
          color:"#007FB1"
          font:
            fontSize:12
            fontWeight:'bold'
          text:"#{moment(program.start_time).format('HH:mm')}〜"

        row.add title
        row.add subtitle
        row.add timeTable
        rows.push row
        
      slide()  
      return $.mainMenu.setData rows
        
slide = (e) ->
  if $.mainMenu.slideState is false
    leftPosition = 200
    $.mainMenu.slideState = true
  else
    leftPosition = 0
    $.mainMenu.slideState = false
  
  transform = Titanium.UI.create2DMatrix()
  animation = Titanium.UI.createAnimation()
  animation.left = leftPosition
  animation.transform = transform
  animation.duration = 300
  
  $.mainMenu.animate(animation)

$.index.open()

f:id:h5y1m141:20140419083319p:plain

f:id:h5y1m141:20140419083332p:plain

Alloyの流儀に従ってUI要素の処理をStylesにうつす

これでも動作するのですが、controllerの中で、UIに関する処理をしてるのがちょっと気持ち悪いので、番組表取得した所のUIの組み立ての処理を一部見直します。

Alloyには、Dynamic Stylesという仕組みがあるのでそれを利用して

  • styles/index.tssに、それぞれのUI要素の色、幅、高さの情報を定義
  • controllers/index.coffeeでのTableViewRowの組み立て時には、上記styles/index.tssで定義したものを反映させる

ということを行います。

styles/index.tssの修正

以下内容を追記します

".programRow":{
    width:Ti.UI.FULL,
    height:80,
    backgroundColor:"f3f3f3"
}
".programTitle":{
    width:220,
    height:50,
    top:5,
    left:70,
    textAlign:'left'
    color:"#222",
    font:{
        fontSize:14
        fontWeight:'bold'
    }
}
".programSUbTitle":{
    width:220,
    height:20,
    top:55,
    left:70,
    textAlign:'left',
    color:"#999",
    font:{
        fontSize:12
    }

}
".programTimeTable":{
    width:60,
    height:20,
    top:20,
    left:5,
    color:"#007FB1",
    font:{
        fontSize:12
        fontWeight:'bold'
    }
}

controllers/index.coffeeの修正

      for program in result.list.g1
        row = $.UI.create 'TableViewRow',
          programID:program.id
          classes:"programRow"
          
        title = $.UI.create 'Label',
          text:"#{program.title}"
          classes:"programTitle"        
            
        subtitle = $.UI.create 'Label' ,
          text:"#{program.subtitle}"
          classes:"programSubTitle"                  
          
        timeTable = $.UI.create 'Label',
          text:"#{moment(program.start_time).format('HH:mm')}〜"
          classes:"programTimeTable"

パッと見わかりづらいかと思いますが、先程までは

Ti.UI.createTableViewRow
  width:xxx

としていた処理を

$.UI.create 'TableViewRow',
  classes:"programRow"

のように、$.UI.create "要素名",

というような形にしてます。

まとめ

Alloyに自作ライブラリを組み込んで利用する方法を紹介しました。今回紹介したNHK番組表APIのようなWebAPI利用するアプリケーションをTitaniumで作る場合に、Titanium のClassicの環境でももちろん出来るのですが、Alloy使うことでより構造化したアプリケーションになると思います。