By

TitaniumであのGunosy風UIを作ってみた

このエントリーをはてなブックマークに追加

甲田です. 今回は, Titaniumでニュースリーダー・GunosyっぽいUIを作ってみてわかったことを書きます.

1. GunosyっぽいUIとはこれだ!

Gunosy(グノシー)とは, Gunosy社が提供するニュース配信サービスです. 僕も使っています. GunosyにはiPhone/Android向けのアプリも存在し, なかなか特徴的なUIを備えています. そのUIとは――

こんなUIです. 下のニュース表示部分をスワイプすると, それと連動して, 上のタブも動いていますね. (Twitterの公式クライアントもこんな感じ) たまにこんなUIを実装する機会があるのですが, どうやって実装するのか結構ハマりました;;

2. どう実装するの??

まず僕が考えたのは, TabGroupを用いた方法です. 一見するとタブとScrollableViewで構成されてるように見えたので.

<TabGroup>  
  <Tab>  
    <ScrollableView />  
  </Tab>  
  <Tab>  
    <ScrollableView />  
  </Tab>  
  ...  
</TabGroup>  

一見, 実現できているように見えますが, まずい点があります. それは スワイプの途中で隣のスクロール先のViewが見えない ということです・・・ これではGunosyを再現するという目的は達成できません.

では, どうするか. web上で情報を探していると, こういう記事を見つけました.
Scrollable Tabs + Draggable Windows example (Titanium Alloy)

3. 使ってみた!

上記の記事を参考にして, 簡単なRSSリーダーアプリを作成してみました. 実は, この記事の冒頭でGunosyのUIの例として挙げたGIFがその画面です.

以下, Githubリポジトリです↓
team-cheekit/likeGunosy

まずはindex.xmlから見ていきます.

<Window id="index" class="container">  
  <ScrollView id="scrollView">  
    <View class="tab" />  
    <View class="split" />  
    ...  
  </ScrollView>  
</Window>  

Gunosy風UIを実現するためには, TabGroupではなくScrollViewの下にViewで擬似的にタブを作る方法をとります. class=”tab”のViewはタブ, class=”split”のViewはタブ間の仕切りです. 参考記事では, Windowの子にScrollableViewを含んでいましたが, 今回はListViewがあり, テンプレートを使い回したかったので, index.jsの方で動的に生成しています.

では, index.jsを見ていきます. まず, 42行目の

Alloy.Globals.currentTabWidth = width;  
if (Ti.Android) {  
  switch(Ti.Platform.displayCaps.dpi) {  
    case 120: width /= 0.75;            break;  
    case 160: width =  width;           break;  
    case 240: width /= width * 1.5;     break;  
    case 320: width /= 2;               break;  
    case 480: width /= 3;               break;  // ここ追加!!  
  }  
  child.setWidth(width);  
}  

adjustTabBarToOrientation()関数は, 端末のdpiに応じてタブの表示サイズを調節します. これは参考記事のコードとほぼ一緒ですが, 参考記事をそのままコピペすると, dpi値の高い端末(Nexus5で確認)では, タブの表示が大きすぎることがあります. そのためswitch文に case 480(Nexus5のdpi) の処理を追加する必要があります.

続いて, Gunosy風UIの重要要素であるスワイプ時のタブとの連動の仕組みを見ていきます. 132行目からのスワイプ時の処理が該当します.

setTabCenter(e.currentPage);            // ScrollableViewの現在のページに対応するタブを画面の中央に.  
var view = $.selected;                  // タブ下の下線を表示するViewを取得  
if (view.parent) {  
  view.parent.remove(view);             // 下線Viewの親(タブのView)から下線Viewを削除  
}  
view.parent = children[e.currentPage];  // 下線Viewの親を, 現在のページに対応するタブに更新
children[e.currentPage].add(view);      // 現在のページに対応するタブに下線Viewを追加

各行の解説はコメントをご覧ください. view.parentは下線Viewが親タブを認識するための独自プロパティ, children配列は, ScrollViewに属するViewのうち, class=”tab”のものだけを取得した配列です. 取得の処理は159行目からのfor文を参照してください.

4. おわりに

コードが長いので全ての処理の解説は省略します. githubリポジトリの方のソースコードに機能単位でコメントを入れておいたので, 気になる方はご覧ください. Titaniumのインストールされた環境でcloneすればすぐに起動できるようにしてあります. (androidのみ動作確認済み)

今回は, GunosyっぽいUIの実現方法について書きました. 良いUIですが参考記事のコードはかなり長いです… そのうちWidget化できたらと思います. 操作性の良いUIだと思いますので, ぜひ使ってみてはいかがでしょうか!