iphone
Development

[iOS] ホーム画面に追加したWebアプリのリンクをSafariに飛ばさない方法

今回はiOSの話と言ってもネイティブアプリじゃなくWebアプリの方です。

iOSのSafariに「ホーム画面に追加」というオプションありますよね。
フルスクリーンで見せたかったりするときは使うべしなんですが、困ったことにリンクをタップすると通常のSafariに戻されるんですよね…

まぁフルスクリーンなので戻るボタンとか無いからの配慮なんでしょうけど、ユーザーはinterruptされるし、フルスクリーンで統一できなくなっちゃうし正直うざいです。

対策その1:Ajaxで逃げ切る

対処法の1つとしてページの内容をXHRでとってきて書き換えればページ遷移は起こりませんよね。

$(document).on('click', 'a', function(e) {
  var $a = $(e.target);
  if (!$a.attr('href').match(/^#/)) {
    e.preventDefault();
    $.get($a.attr('href'), function(data) {
      var $body = $('body');
      $body.children().remove();
      $body.append($(data));
    })
  }
});

試してないけど多分こんなかんじでしょうか。
でもこれだとサーバーサイドも合わせなくちゃいけなくてめんどくさいなーとか、ページ遷移したと見せかけてwindowのonloadイベントとか発火されないし $(document).ready() みたいのは動かないですよね。

対策その2(おすすめ):一旦preventDefaultしてからのlocationに突っ込む

でたどり着いたのがこれです。
どうやら一旦preventDefaultしてしまったらページ遷移してもSafariに飛ばされないみたいです。

$(document).on('click', 'a', function(e) {
  var $a = $(e.target);
  if (!$a.attr('href').match(/^#/)) {
    e.preventDefault();
    window.location = $a.attr('href');
  }
});

いい感じに動いてます

標準
Native American 12
Development

JavaScriptでネイティブアプリを開発できるTitanium MobileとAlloyをつかってみよう その3

前回はalloy generateコマンドでcontrollerとviewとstyleを生成してモーダルウィンドウを表示してみました。
今回は右から新しいウィンドウがスライドして現れる画面遷移を作成してみたいと思います。

コントローラーの初期状態

まずはメインのコントローラであるindex.jsの中身を以下のようにして、初期画面を表示するだけにしてみます。

$.index.open();

スクリーンショット 2014-01-31 10.09.19

ここで使っている $ はalloyの提供するBaseControllerクラスを継承したindexコントローラのインスタンスです。
また$.indexはビュー内のWindowにid属性がふられていない場合にビューファイルの名称でWindowオブジェクトにアクセスできるようです。

ビューを画面遷移に対応させる

ビューファイルを以下のように書き換えて右へ右へと画面遷移を出来るように準備します。

<Alloy>
    <NavigationWindow id="navigationWindow" platform="ios">
        <Window class="container" title="First Win">
             <Button title="click me" />
         </Window>
     </NavigationWindow>
</Alloy>

WindowをNavigationWindowというオブジェクトでラップしています。こうすることで画面上部にタイトルや前の画面に戻るためのナビゲーションバーが表示されるようになります。

ビューファイルでNavigationWindowを追加し、id属性を定義したのでコントローラーで $.index.open() のままだとエラーしてしまいます。
なので「navigationWindowというidのWindowを開く」というコードに変更します。

controllers/index.js

$.navigationWindow.open();

ビルドしてみると以下のように表示されます。

スクリーンショット 2014-01-31 10.27.42

 

ボタンのイベントハンドラを定義

そして中央に配置したボタンのタグにonClick属性を追加してここをタップすると遷移する動作を行うようにしてみます。

<Button title="click me" onClick="openWin" />

またコントローラーに戻って以下のようにボタンに紐付けたイベントハンドラを定義してみます。

function openWin(e) {
  console.log(e);
}

まずは単に受け取ったイベントオブジェクトをconsole.logしてみるだけにしました。このままビルド(titanium build -p ios)してボタンを押すと以下のようなログが出力されます。

[INFO] {
[INFO]     bubbles = 1;
[INFO]     cancelBubble = 0;
[INFO]     source = "[object __alloyId1]";
[INFO]     type = click;
[INFO]     x = "38.5";
[INFO]     y = "20.5";
[INFO] }

今回は特にイベントオブジェクトの中身に応じて処理を切り替えることはしませんが、こうして書いたコードを一つ一つビルドして確認すればなにか不具合が起きた時に手戻りが少なくて済むようになる事が多いのでなるべくこまめにconsole.logをするようにしています。

さて、このopenWinの中で新たなWindowを生成し画面遷移を起こさせてみたいと思います。

function openWin(e) {
  var win = Ti.UI.createWindow({
     title: 'Sub Win',
     backgroundColor: '#fff'
   });
   $.navigationWindow.openWindow(win);
}

TiとはTitaniumオブジェクトのエイリアスでどちらでも同じものです。Ti.UIというオブジェクトに様々なビューオブジェクトを生成するcreateXxxといったメソッドが定義されています。createWindowメソッドを使うと真っ黒で何も無いWindowが生成されるのでtitleに「Sub Win」、背景色を白に設定しました。

次に$.navigationWindowのopenWindowメソッドに生成した新しいWindowを渡すことでアニメーション付きで画面遷移をしてくれるようになります。
画面遷移の途中は早すぎてキャプチャできないですが遷移後は以下の様な画面が表示されます。

スクリーンショット 2014-01-31 10.49.34

真っ白なWindowを生成しただけですが左上に最初の画面に戻るためのボタンが用意されていますね。これがモーダルにはないNavigationWindowの特徴です。

まとめ

今回紹介した画面遷移はかなりポピュラーなUIデザインパターンなのでこれを覚えておくだけでも簡単なアプリが作れてしまいそうですよね。
しかしNavigationWindowはiOSにしか定義されていないクラスのようです。Androidは端末そのものに戻るボタンを実装しアプリケーション側では意識する必要がないようにデザインされているためでしょう。

要約すると

  1. NavigationWindowにidをふる
  2. コントローラーからふったidを参照して初期画面を表示する
  3. ボタンのonClick属性でイベントハンドラを定義する
  4. 新しいウィンドウを生成してNavigationWindowのopenWindowメソッドに渡す

以上です。

標準