imthinker::net

ふらふらうぇぶろぐ

Titanium 3.1 で登場予定の ListView を見てみよう

先月の tiTokyo でもチラリと発表されていましたが、 Titanium 3.1 では TableView に変わるデータ列挙用の UI コンポーネントとして、 ListView というものが登場する予定です。そして、最近の Continuous Builds でその実装が一部始まったようなので早速試してみました。

ListView とは

そもそも ListView とはなんでしょうか?これまで、例えば Twitter クライアントのようなアプリケーションを構築しようと思ったら、 TableView を使って Row の上に様々な View を配置していくスタイルが Titanium では一般的でした。

多目的に使われる TableView ですが、複雑なレイアウトやイベント処理の関係でパフォーマンスに悪い影響を与えることも少なくありませんでした。そこで登場するのが ListView です。 ListView はパフォーマンスにフォーカスを当てて開発が進められています。

テンプレート

ListView の特徴はテーブル上に表示される項目を「テンプレート」という形で予め定義しておける点にあります。これまで、 TableViewRow の上に ImageView を置いて、 Label を置いて…という1つ1つ行っていた処理を簡略化することが可能です。

これは、 Ti.UI.ListViewTemplate というオブジェクトで実装することが可能になるようですが、現在の Continuous Builds では未実装でした。また、今後の仕様変更によって実装されるかどうかも分かりません。

var listTemplate = {
    properties: {
        onDisplayItem: function (e) {
            console.log(e);
        },
        selectedBackgroundColor: "blue",
        height: 44
    },
    events: {},
    childTemplates: [{
        type: "Ti.UI.Label",
        id: "cellLabel",
        properties: {
            color: "#FF3300",
            font: {
                fontFamily: "Helvetica",
                fontSize: 16,
                fontWeight: "bold"
            },
            textAlign: "center",
            width: Ti.UI.FILL,
            height: Ti.UI.SIZE,
            top: 0,
            left: 0
        },
        events: {
            click: function (e) {
                console.log(e);
            }
        }
    }]
};

例えば、このようなオブジェクトリテラルを定義しておくとします。そして、 ListView を定義するときに、これをテンプレートとして取り込むことができます。

var listView = Ti.UI.createListView({
    templates: {
        myTemplate1: listTemplate
    },
    sections: [listSection]
});

テンプレートは複数定義しておいて、 ListView のアイテムを定義するときに使用することができます。上記コードで sections というプロパティを定義し、値に配列、その中に listSection を代入しています。 listSection は以下のようになります。

var listSection = Ti.UI.createListSection({
    headerTitle: "List View Section"
});

TableView では TableView を作ったら、その中に TableViewRow をガシガシ突っ込んでいくスタイルでしたが、 ListView では ListView の中に最低1つの Section を作って、 Section の中にアイテムを入れます。ここでは headerTitle を付けていますが、付けなくても大丈夫です。

Section へのアイテム代入は setItems メソッドで行います。

listSection.setItems([{
    template: "myTemplate1",
    cellLabel: {
        text: "Label text 1",
    }
}, {
    template: "myTemplate1",
    cellLabel: {
        text: "Label text 2",
    }
}]);

予めテンプレートを定義しておいて、そのテンプレートを使ってアイテムを構築し、アイテムをセクションに代入し、セクションを ListView に渡すことでデータを列挙するというのが ListView の仕組みのようです。

デフォルトテンプレート

現在の Continuous Builds はまだ独自のテンプレートが動かないようで、今まで書いたコードは残念ながら動作確認ができていません。 Continuous Builds でビルドすることでエラー無く動作はするものの、テンプレートとして定義している Label が表示されない状態です。

そこで、予め定義されているデフォルトテンプレートを試してみました。以下は動くコードです。これを app.js として保存し、 Continuous Builds で動作させることでスクリーンショットのような動きを見せます。

/*jslint devel:true */
/*global Titanium */
(function (Ti) {
    "use strict";
    var win, listSection, listTemplate, listView;
    win = Ti.UI.createWindow({
        backgroundColor: "#FFFFFF"
    });

    listSection = Ti.UI.createListSection({
        headerTitle: "List Header Title"
    });

    listView = Ti.UI.createListView({
        sections: [listSection],
        backgroundColor: "#FFFFFF"
    });

    listView.addEventListener("itemclick", function (e) {
        var idx, section, data;
        idx = e.itemIndex;
        section = e.section;
        data = section.getItemAt(idx).properties;
        alert("You clicked \"" + data.title + "\"");
    });

    listSection.setItems([{
        template: Ti.UI.LIST_ITEM_TEMPLATE_DEFAULT,
        properties: {
            title: "Default Title",
            subtitle: "Default Sub Title"
        }
    }, {
        template: Ti.UI.LIST_ITEM_TEMPLATE_SETTINGS,
        properties: {
            title: "Settings Title",
            subtitle: "Settings Sub Title"
        }
    }, {
        template: Ti.UI.LIST_ITEM_TEMPLATE_CONTACTS,
        properties: {
            title: "Contacts Title",
            subtitle: "Contacts Sub Title"
        }
    }, {
        template: Ti.UI.LIST_ITEM_TEMPLATE_SUBTITLE,
        properties: {
            title: "Subtitle Title",
            subtitle: "Subtitle Sub Title"
        }
    }, {
        template: Ti.UI.LIST_ITEM_TEMPLATE_DEFAULT,
        properties: {
            title: "Accessory Type None",
            accessoryType: Ti.UI.LIST_ACCESSORY_TYPE_NONE
        }
    }, {
        template: Ti.UI.LIST_ITEM_TEMPLATE_DEFAULT,
        properties: {
            title: "Accessory Type Checkmark",
            accessoryType: Ti.UI.LIST_ACCESSORY_TYPE_CHECKMARK
        }
    }, {
        template: Ti.UI.LIST_ITEM_TEMPLATE_DEFAULT,
        properties: {
            title: "Accessory Type Detail",
            accessoryType: Ti.UI.LIST_ACCESSORY_TYPE_DETAIL
        }
    }, {
        template: Ti.UI.LIST_ITEM_TEMPLATE_DEFAULT,
        properties: {
            title: "Accessory Type Disclosure",
            accessoryType: Ti.UI.LIST_ACCESSORY_TYPE_DISCLOSURE
        }
    }]);

    win.add(listView);
    win.open();
}(Titanium));

f:id:RyuGoo:20130316013407p:plain

f:id:RyuGoo:20130316013442p:plain


どうでしょうか。予め用意されているテンプレートの形に従ってアイテムの表示が変わっていることが分かります。 ListView の addEventListener に itemclick というイベントハンドラを設定していますが、これは新しいハンドラです。

ListView 本体に addEventListener を置いていますが、テンプレートを定義する場合は childTemplates に Label や ImageView などの子テンプレートを定義し、パーツ毎にイベントハンドラを設定できるようなので、本当に細かい設定までできることになりそうです。

最後に

今回は発展途上中の Continuous Builds を使い、さらに発展途上中の API をつまみ食いしてみましたが、久しぶりに TableView のような大きな UI パーツ系に新しい要素が入ってきたので大変楽しいものでした。

現時点でこれを実用しようだなんて間違っても考えてはいけません。絶対に仕様変更があるはずですし、痛い目を見るのは分かっていることです。しかし、新しい API が登場したときに混乱しなくて済むように、事前のキャッチアップはお勧めします。

CODESTRONG!