Google+ もご覧ください
ユーザーアイコン

Ti Weekly Clips++

ListViewの使い方をマスターする!(前編)&Titanium周りで知っておきたいニュース色々

Donayama

ListViewの使い方をマスターする!(前編)&Titanium周りで知っておきたいニュース色々

News - SDKアップデートやイベントなどのニュース

Device deployment broken by recent iTunes update 11.2

最新版のiTunes 11.2環境では実機デバッグビルドがうまいこと行えない状態になっているようです。 (配布用ビルドは問題ないようです)

本対策は3.2.4もしくは3.3.0でされるようです(実際継続ビルド版の3.2.4で改善されています)が、それまでの対応策としては11.1に戻す、もしくはAdHocビルドを介したインストールをすることが示されています。

Tips & Topics - ノウハウや技術紹介、解説記事

DynamicLabel tag in Alloy - allows you to update a "value" and it applies it to a template. Place ui.js in your app/lib folder

AlloyでWidgetとして作るまでもない簡易的な表示ならこういう手段もあるんですね。 ちなみにDemonstrate CollapsableView Tag in Alloy.という同様のアプローチをしているサンプルも作られています。

ライフサイクルの管理がどうなるのかちょっと気になりますが。

TitaniumSDK・Alloyのバージョン、gitのブランチ名を表示する.bash_profile

Tony LukasavageさんのGistにあがっていたシェルスクリプト。

GitHub Watch - モジュールやサンプルコードの情報

k0sukey/TiTodoMVC

浜松の勉強会でハンズオンに使われたTODO管理アプリ。

coolelephant/CETandemScrollView

一枚の背景画像を左右にスライドさせながら表示できるScrollableViewのようなiOSネイティブモジュール。 百聞は一見に如かずということで、デモ画像をご覧ください。

benbahrenburg/Utterance

合成音声再生モジュールであるUtteranceがAndroidにも対応したようです。

mwaylabs/titanium-barcode

バーコード読み取りを行うAndroid専用のモジュール。

tonylukasavage/ti-logger

TitaniumとNode.jsで共用できるログ出力モジュール。鋭意開発中とのこと。

Spotlight - 小さな特集

今回と次回の特集ではElements Of ListViewにあるPDFドキュメントのざっくり和訳を前後編でお送りします。

本ドキュメントはAppceleratorのThomas D Wilkinsonさんによって書かれたものです。

概要

ListViewはそれまで使ったことがないひとにとって、ちょっと手強いです。 その構造が完全にTableViewやその他のTitanium.UI要素とは違うためです。

敷居の高さを感じさせるのは、表示に関する(物理的な)部品作成をする必要がなくなる変化でしょう。 Viewの代わりにベースとなるテンプレートを用意し、そこに流し込むデータを用意するという流れになります。

TableViewにおいて、テーブル自体が大きくなりすぎたとき性能やメモリ消費に影響がありますが、 この問題を解決するためListViewコントロールは設計され(上記のようなアプローチになっています)ました。

このドキュメントでは標準的なリストからカスタムテンプレートやイベントハンドリングを行う方法まで、テンプレートとデータの取り扱い方法について説明します。 これによってTitanium SDKの最もパワフルな機能をマスターすることができるでしょう。

なお、使用するサンプルプロジェクトはGitHubで公開されています。 各Chapterごとにブランチを分けていますので、随時checkoutしてください。

https://github.com/appcelerator-services/ElementsOfListView/

(このチュートリアルでは、実際のクロスプラットフォームアプリケーション開発を想定して進めて行きます)

Chapter.1 Hello World

(gitブランチ: 01-HelloWorld)

まずは文字列のリストを表示する標準的なリストからはじめていきましょう。

このときのViewのxmlは次のようになります。この時点ではAlloyの他の要素と違いはありませんね。

<ListView id="elementsList">
  <ListSection name="elements">
    <ListItem title="Hydrogen"/>
    <ListItem title="Helium"/>
    <ListItem title="Lithium"/>
    ...
 </ListSection>
</ListView>

Chapter.2 テンプレートでレイアウトをカスタマイズする

(gitブランチ: 02-ListTemplate)

表示方法をカスタマイズする場合、リストアイテムの外観をItemTemplateとして定義する必要があります。

ItemTemplateはAlloy Viewによく似ていますが、大きな違いとしてbindIdがあります。 このbindId属性はリストデータを接続するために使用するためのものです。

<ListView id="elementsList">
 <Templates>
   <ItemTemplate name="elementTemplate">
     <Label bindId="symbol" id="symbol" />
     <View id="atomProperties">
       <Label bindId="name" id="name" />
       <View id="secondLine">
         <Label class="line2 fieldLabel" text="Number: " />
         <Label class="line2" bindId="number" id="number" />
         <Label class="line2 fieldLabel" text="Atomic Mass: " />
         <Label class="line2" bindId="mass" id="mass" />
       </View>
     </View>
   </ItemTemplate>
 </Templates>
 <ListSection name="elements" />
</ListView>

テンプレート内の要素は他の要素と同様にTSSスタイルシートを用いてプロパティ設定を行うことができます。 その際にはidclassを指定することもできます。

続いて、どのテンプレートを使うのかについて、スタイルのdefaultItemTemplateプロパティで指定します。 もし指定しない場合は標準のテンプレートを使おうとします。

複数のテンプレートがある場合、ListItemのテンプレート属性を設定することで使用するテンプレートを指定できます。

  "#elementsList": {
    backgroundColor:"white",
    defaultItemTemplate:"elementTemplate",
    separatorColor: "#999"

テンプレートの各種データを設定するためにはListItemに追加情報を指定する必要があります。

<ListItem symbol:text="Ti" name:text="Titanium" number:text="22"
          mass:text="47.867"/>

このListItemの各属性はテンプレートのbindIdを参照します。 :textは対象のオブジェクト(ここではLabel)のtextプロパティを指し示しています。

たとえばname:text<Label bindId="name" id="name" />のLabelのtextプロパティに"Titanium"を設定するという意味になります。

<Label text="Titanium" />

Labelのtextプロパティに限定されません。任意の値を設定できます。 水素"H"の表示色を設定する場合は次のようになります。

<ListItem symbol:text="H" symbol:color="#090" name:text="Hydrogen"
          number:text="1" mass:text="1.00794"/>

もちろんLable以外のオブジェクトにも値を設定することができます。

影付きの背景を設定する必要がある場合は、wrapperView:backgroundColor="#e8e8ff"のようにします。

Chapter.3 コンテンツを更新する

(Gitブランチ: 03-LiveData)

これまでの例ではListItemがviewのxmlに直接記述されていました。

これではプレゼンテーションとデータが分離されていませんし、動的なデータを表現できていませんので、プログラムに手を入れたいと思います。

ListItemはTableViewRowと違ってViewではないため、ListViewを介してデータセットを送り込むことでListItemに影響を与えるかたちになります。

それではListViewにこれらのデータを取り込んでみましょう。

elements.table = [
  {"name":"Hydrogen","number":1,"symbol":"H","mass":1.00794},
  {"name":"Helium","number":2,"symbol":"He","mass":4.002602},
  {"name":"Lithium","number":3,"symbol":"Li","mass":6.941},
  ...
]

上記のリストで定義されたelements.tableをListViewで動作するように少し加工する必要があります。といってもbindIdごとのプロパティマッピングを行うだけです。

var items = _.map(elements.table, function(element) {
  return {
    symbol: {text: element.symbol},
    name:   {text: element.name},
    number: {text: element.number},
    mass:   {text: element.mass}
  };
});

加工されたitemsを最初のListSectionのListItemとして設定します。

$.elementsList.sections[0].setItems(items);

上記の例ではLabelのtextを設定できるだけで、すべてのsymbolは黒色で表現されていました。

色変更の方法ですが、symbol: {text: element.symbol, color: “#090”}といったように単純にcolorプロパティを追加するのみになります。

しかし、色をリアルタイムに変えたいような場合はこれでは実現できません。

温度の設定を画面上のスライダで変更すると固体〜液体〜気体へ変動して行きます。

動的に変更するにまずListItemのデータを一つずつ取得し、更新をしていきます。

var changeColor = function(itemIndex, color) {
  var listSection = $.elementsList.sections[0];
  var listItem = listSection.getItemAt(itemIndex);
  listItem.symbol.color = color;
  listSection.updateItemAt(itemIndex, listItem);
};

実はこの方法はコストの高い処理になります。 スライダーのchangeイベントに対して、118元素の更新を逐一実施したところ手元の最速のAnroid端末(HTC One M8)で10〜15秒要しました。

これを実際に色が変わる項目のみを更新するようにしたところ、250msにまで処理時間を短縮することができました。

var changeColor = function(itemIndex, color) {
  var listSection = $.elementsList.sections[0];
  var listItem = listSection.getItemAt(itemIndex);
  if(listItem.symbol.color != color) {
    listItem.symbol.color = color;
    listSection.updateItemAt(itemIndex, listItem);
  }
};

さらに、すべてのデータをsetDataで置き換えることにより、Androidでは100msまで短縮できました。 (iPhone5Sでは10ms未満)

このような理由から、数件のデータ修正でないのであれば、全体的なデータ更新をすることを推奨します。

サンプルコードには上記に挙げた3つの更新アプローチ(すべてのアイテムを逐一更新する、変更のあったアイテムのみ更新、全体的なデータセットを差し替える)に関する説明をコメントとして記述しています。 changeTemperatureActionメソッド内のifブロックを切り替えて動きの違いを見てみてください。

var changeTemperatureAction = function() {

    // 処理時間測定用
    var startTime = new Date();

    changeTemperatureTimer = null;

    var numChanges = 118; // 更新件数保持

    if(false) {
        // 方法1: 118項目すべてのListItemを更新する
        _.map(elements.table, function(element) {
            changeColor1(element.number-1, temperatureColor(element, temperature));
        });
    }

    if(true) {
        // 方法2: 更新されたアイテムだけ更新する
        numChanges = 0;
        _.map(elements.table, function(element) {
            if(changeColor2(element.number-1, temperatureColor(element, temperature))) {
                numChanges++;
            }
        });
    }

    // 方法3: setItemsですべて一気に更新する
  if(false) {
        setItems();
    }

    // 所要時間のログ表示
    var endTime = new Date();
    Ti.API.info("index::changeTemperatureAction complete, changed "+numChanges+" element states in " +
            (endTime.valueOf() - startTime.valueOf()) + "ms.");
};

(次回に続く)

Tiweeklyclips

記事をリクエストする

関連記事

コメント