The sky is the limit

ハイブリッドアプリ開発、PWAなど効率の良いiOSアプリ、Androidアプリ開発の情報を共有したい。アプリ開発は楽しい。【PWA、AngularJS、Monaca、Cordova、OnsenUI】

1-2【UI開発】OnsenUIを使ったページ遷移の実装2 【Navigator編】- 【連載】ハイブリッドアプリ開発で貯金管理アプリを作る【Cordova・Monaca・OnsenUI・AngularJS】 -

【連載】ハイブリッドアプリ開発で貯金管理アプリを作る【Cordova・Monaca・OnsenUI・AngularJS】

f:id:duo-taro100:20160218004611p:plain

1章 UI開発

1-2【UI開発】OnsenUIを使ったページ遷移の実装2【Navigator編】


このページは、過去の記事

www.sky-limit-future.com

を最新化したもの。
www.sky-limit-future.com
こちらの続きとなっている。

ナビゲーション型画面遷移

以下、ドキュメントから引用

コンポーネントは、ページスタックの管理機能と、画面遷移時のアニメーション効果を提供します。ページスタックに新しいページが追加されると、自動的にアニメーションが行われ、ページが表示されます。スタック内のすべてのページは要素で表されます。そのため、コンポーネントの直下にはコンポーネントのみ配置できます。
通常は、ページ上部にツールバーを設置します。そのため、の下にはコンポーネントを配置するのが一般的です。ツールバーには、戻るボタンを設置したり、ページタイトルを描画したりします。

ja.onsen.io.s3-website-us-east-1.amazonaws.com

index.htmlは前回の記事と同様のものを使う。

主にNavigatorのpushPage()とpopPage()を使用する。
例えば、一覧画面でリストを押下した場合、押下したアイテムの詳細画面に遷移する場合はpushPage()を使う。
注意点は、Navigatorで遷移した場合は、tabbarやtoolbarが表示されなくなることこれはtabbarのカバー範囲外に行くから。
もしtabbarを表示したまま画面遷移したい場合は、前回の記事で説明したように、ng-clickに遷移するためのメソッドを定義する。

ons-navigator

共通ページをons-navigatorタグで囲っている。
var属性で指定した「myNavigator」をangular側で拾って、イベント定義などを実装する。

<!-- 共通ページ -->
<ons-navigator var="myNavigator">
    <ons-page ng-controller="pageCtrl as pctrl">
       <ons-toolbar id="toolbar">
          <div class="center">{{pctrl.title}}</div>
            <!-- 一覧ページから詳細ページへの遷移ボタンを実装 -->
          <div class="right" ng-if="pctrl.title == '一覧'">
                <ons-button ng-click="myNavigator.pushPage('listDetail.html');">詳細画面へ</ons-button>
            </div>
        </ons-toolbar>

        <ons-tabbar position="bottom">
            <ons-tab page="home.html" label="ホーム" icon="home" active></ons-tab>
            <ons-tab page="list.html" label="一覧" icon="list"></ons-tab>
            <ons-tab page="history.html" label="履歴" icon="history"></ons-tab>
            <ons-tab page="simulation.html" label="計算" icon="calculator"></ons-tab>
            <ons-tab page="config.html" label="設定" icon="gear"></ons-tab>
        </ons-tabbar>
    </ons-page>
</ons-navigator>
pushPage()とpopPage()

pushPage()は新しいページを表示する。popPage()は遷移前のページを表示する。(戻る)
よく使うoptionとしてはanimationとdata。
animationは画面表示時の動きを決める。
dataは遷移先へのデータの受け渡しを行う。

ドキュメントを読めばわかると思うが。
https://ja.onsen.io/v2/api/angular1/ons-navigator.html#method-pushPage

	<ons-button ng-click="myNavigator.pushPage('listDetail.html');">詳細画面へ</ons-button>

これはoptionなし。
animationには

slide
fade
lift

などがある。
ここでは試さないが、例えばslideを指定する場合はこんな感じ

	<ons-button ng-click="myNavigator.pushPage('listDetail.html', {animation:slide});">詳細画面へ</ons-button>

データを次の画面に渡したいときはdataオプションを使う。

◆html

<!-- 共通ページ -->
<ons-navigator var="myNavigator">
    <ons-page ng-controller="pageCtrl as pctrl">
       <ons-toolbar id="toolbar">
          <div class="center">{{pctrl.title}}</div>
            <!-- 一覧ページから詳細ページへの遷移ボタンを実装 -->
          <div class="right" ng-if="pctrl.title == '一覧'">
                <ons-button ng-click="myNavigator.pushPage('listDetail.html',{data: {name: 'duotaro',age: '22'}})">詳細画面へ</ons-button>
            </div>
        </ons-toolbar>

        <ons-tabbar position="bottom">
            <ons-tab page="home.html" label="ホーム" icon="home" active></ons-tab>
            <ons-tab page="list.html" label="一覧" icon="list"></ons-tab>
            <ons-tab page="history.html" label="履歴" icon="history"></ons-tab>
            <ons-tab page="simulation.html" label="計算" icon="calculator"></ons-tab>
            <ons-tab page="config.html" label="設定" icon="gear"></ons-tab>
        </ons-tabbar>
    </ons-page>
</ons-navigator>

<!-- 詳細画面画面 -->
<ons-template id="listDetail.html">
    <ons-page id="detailPage" ons-show="pctrl.title = '詳細'">
        <div class="content" ng-app="myApp">
            <div class="main" ng-controller="listDetailCtrl as ldctrl">
                <p>詳細画面</p>
                <p>{{ldctrl.name}}</p>
                <p>{{ldctrl.age}}</p>
            </div>
        </div>
    </ons-page>
</ons-template>
	
<script src="js/controller/listController.js"></script>

以下、サンプルコード
listController.js

	myApp.controller('listDetailCtrl', function(){ 

      this.name = '初期名称';
      this.age = '0';
      // myNavigator.pushPageで送ったdataを受け取る 
      var data = myNavigator.topPage.data;
      // 正しく受け取ることができたら、値を取得
      if(data != undefined){
          this.name = data.name; 
          this.age = data.age; 
      }
		
	});

index.htmlでlistController.jsを読み込むのを忘れないように。(よくやる)
詳細画面には、ng-controller属性を追加した。

<div class="main" ng-controller="listDetailCtrl ac ldctrl">
    <p>詳細画面</p>
    <p>{{ldctrl.name}}</p>
    <p>{{ldctrl.age}}</p>
</div>

こうすれば、listDetailCtrlで定義した値がindex.htmlで使えるようになる。
実際に遷移してみると、問題があるのが分かると思う。
元の画面にもどれない。

f:id:duo-taro100:20170831223928p:plain

この画面はタブが表示されないので、遷移前の戻る用ボタンを設置する必要がある。
toolbarにある方が、画面全体の有効活用が可能なので、この画面にはtoolbarを独自で持つようにした。

<!-- 詳細画面画面 -->
<ons-template id="listDetail.html">
    <ons-page id="detailPage" ons-show="pctrl.title = '詳細'">
        <!-- START toolbar追加 -->
        <ons-toolbar id="toolbar">
            <!-- 一覧ページへの戻るボタンを実装 -->
            <ons-back-button>戻る</ons-back-button>
            <div class="center">{{pctrl.title}}</div>
        </ons-toolbar>
        <!-- END toolbar追加 -->
        <div class="content" ng-app="myApp">
            <div class="main" ng-controller="listDetailCtrl as ldctrl">
                <p>詳細画面</p>
                <p>{{lectrl.name}}</p>
                <p>{{lectrl.age}}</p>
            </div>
        </div>
    </ons-page>
</ons-template>

これで問題はなくなった。
ちゃんとデータの受け渡しもできている。
f:id:duo-taro100:20170831224210p:plain

上記の実装ではタグを使用して、遷移前の画面に戻っているが、popPage()を使っても実装可能。

    <!-- 詳細画面画面 -->
    <ons-template id="listDetail.html">
        <ons-page id="detailPage" ons-show="pctrl.title = '詳細'">
            <ons-toolbar id="toolbar">
                <!-- 一覧ページへの戻るボタンを実装 -->
                <ons-button ng-click="myNavigator.popPage()">戻る</ons-button>
                <div class="center">{{pctrl.title}}</div>
            </ons-toolbar>
            <div class="content" ng-app="myApp">
                <div class="main" ng-controller="listDetailCtrl as ldctrl">
                    <p>詳細画面</p>
                    <p>名前:{{ldctrl.name}}</p>
                    <p>年齢:{{ldctrl.age}}</p>
                </div>
            </div>
        </ons-page>
    </ons-template>


ここで、前回と本記事までの実装内容をまとめる。
(controllerはデータ受け渡し用のサンプルで作成しただけなので、ここではなかったものとする)

前回
www.sky-limit-future.com


index.html

<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
  <script src="components/loader.js"></script>
  <script src="lib/angular/angular.min.js"></script>
  <script src="lib/onsenui/js/onsenui.min.js"></script>
  <script src="lib/onsenui/js/angular-onsenui.min.js"></script>

  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsenui.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css">
  <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <!-- 共通ページ -->
    <ons-navigator var="myNavigator">
        <ons-page ng-controller="pageCtrl as pctrl">
           <ons-toolbar id="toolbar">
              <div class="center">{{pctrl.title}}</div>
                <!-- 一覧ページから詳細ページへの遷移ボタンを実装 -->
              <div class="right" ng-if="pctrl.title == '一覧'">
                    <ons-button ng-click="myNavigator.pushPage('listDetail.html')">詳細画面へ</ons-button>
                </div>
            </ons-toolbar>

            <ons-tabbar position="bottom">
                <ons-tab page="home.html" label="ホーム" icon="home" active></ons-tab>
                <ons-tab page="list.html" label="一覧" icon="list"></ons-tab>
                <ons-tab page="history.html" label="履歴" icon="history"></ons-tab>
                <ons-tab page="simulation.html" label="計算" icon="calculator"></ons-tab>
                <ons-tab page="config.html" label="設定" icon="gear"></ons-tab>
            </ons-tabbar>
        </ons-page>
    </ons-navigator>

    <!-- ホーム画面 -->
    <ons-template id="home.html">
        <ons-page id="homePage" ons-show="pctrl.title = 'ホーム'">
            <div class="content" ng-app="myApp">
                <div class="main">
                    <ons-button ng-click="pctrl.changeConfigTab()">設定画面へ</ons-button>
                </div>
            </div>
        </ons-page>
    </ons-template>

    <!-- 一覧画面 -->
    <ons-template id="list.html">
        <ons-page id="listPage" ons-show="pctrl.title = '一覧'">
            <div class="content" ng-app="myApp">
                <div class="main">
                    <ons-button ng-click="myNavigator.pushPage('listDetail.html');">詳細画面へ</ons-button>
                </div>
            </div>
        </ons-page>
    </ons-template>

    <!-- 詳細画面画面 -->
    <ons-template id="listDetail.html">
        <ons-page id="detailPage" ons-show="pctrl.title = '詳細'">
            <!-- START toolbar追加 -->
            <ons-toolbar id="toolbar">
                <!-- 一覧ページへの戻るボタンを実装 -->
                <ons-back-button>戻る</ons-back-button>
                <div class="center">{{pctrl.title}}</div>
            </ons-toolbar>
            <!-- END toolbar追加 -->
            <div class="content" ng-app="myApp">
                <div class="main">
                </div>
            </div>
        </ons-page>
    </ons-template>

    <!-- 編集画面 -->
    <ons-template id="listEdit.html">
        <ons-page id="editPage" ons-show="pctrl.title = '編集'">
            <div class="content" ng-app="myApp">
                <div class="main">
                    <p>編集画面</p>
                </div>
            </div>
        </ons-page>
    </ons-template>

    <!-- 履歴画面 -->
    <ons-template id="history.html">
        <ons-page id="historyPage" ons-show="pctrl.title = '履歴'">
            <div class="content" ng-app="myApp">
                <div class="main">
                    <ons-button ng-click="myNavigator.pushPage('chart.html');">グラフ画面へ</ons-button>
                </div>
            </div>
        </ons-page>
    </ons-template>

    <!-- グラフ画面 -->
    <ons-template id="chart.html">
        <ons-page id="chartPage" ons-show="pctrl.title = 'グラフ'">
            <div class="content" ng-app="myApp">
                <div class="main">
                    <p>グラフ画面</p>
                </div>
            </div>
        </ons-page>
    </ons-template>

    <!-- 計算画面 -->
    <ons-template id="simulation.html">
        <ons-page id="simPage" ons-show="pctrl.title = '計算'">
            <div class="content" ng-app="myApp">
                <div class="main">
                    <p>計算画面</p>
                </div>
            </div>
        </ons-page>
    </ons-template>

    <!-- 設定画面 -->
    <ons-template id="config.html">
        <ons-page id="configPage" ons-show="pctrl.title = '設定'">
            <div class="content" ng-app="myApp">
                <div class="main">
                    <p>設定画面</p>
                </div>
            </div>
        </ons-page>
    </ons-template>
<script>
    // モジュールの定義
    var myApp = ons.bootstrap('myApp',[]);

    /**
     * 画面遷移用コントローラ
     */ 
    myApp.controller('pageCtrl', function() {

        // タブバーを取得
        var tabbar = document.querySelector("ons-tabbar");

        // 1つ目のタブへ遷移
        this.changeHomeTab = function(){
            tabbar.setActiveTab(0);
        };
        // 2つ目のタブへ遷移
        this.changeListTab = function(){
            tabbar.setActiveTab(1);
        }
        // 3つ目のタブへ遷移
        this.changeHistoryTab = function(){
            tabbar.setActiveTab(2);
        }
        // 4つ目のタブへ遷移
        this.changeSimTab = function(){
            tabbar.setActiveTab(3);
        }
        // 5つ目のタブへ遷移
        this.changeConfigTab = function(){
            tabbar.setActiveTab(4);
        }
    });
</script>
</body>
</html>
<script src="js/controller/listDetailController.js"></script>

ここまでで、アプリの骨格ができた感じ。

Angularの実装方針

余談。僕がAngularで$scoreを使わなかったり、ng-controllerの中で「as」を使っている実装方針は

qiita.com


ここを参考にさせていただいた。この記事を見てAngularを始めようと思ったのを覚えている。
こちらの記事もすでに2年前のものになっているので。現在はどういったものがベストなのか考える必要があるかも。
今後はAngular2やvue.jsを使ったハイブリッドアプリ開発とPWA開発をやっていきたい。

以上。