[monaca]ui-routerで詳細スワイプ処理

リストが見れたら、その詳細も見たいよね！…って事で、詳細画面（スワイプ処理付）を作ってみました。

# ベース

ui-routerでjsonを取得したリスト画面
[[monaca]ui-routerでjson取得処理。](https://qiita.com/miz21358/items/33eeb650df3b6e3ccf58)

# angular-sanitizeの導入

詳細画面では、JSONから取得したHTMLタグを含む文字列を表示します。
通常AngularJSでは、HTMLタグはエスケープ処理をされますが、HTMLタグを有効にするため、サニタイズ用モジュールを導入します。

参考) [ビューにHTML文書をバインドするには？（ng-bind-html）](http://www.buildinsider.net/web/angularjstips/0007)

![sanitize01.png](https://qiita-image-store.s3.amazonaws.com/0/184714/e375d3ff-aef6-410b-a971-d66701fe0aee.png)

![sanitize02.png](https://qiita-image-store.s3.amazonaws.com/0/184714/2fc0628b-64b9-784e-1b92-593e27030f6d.png)

* 2017/09/22時点での導入可能最新バージョンは、1.6.6です
* buildを含むバージョンは導入できません。

![sanitize03.png](https://qiita-image-store.s3.amazonaws.com/0/184714/4d1e9130-2abd-46f6-a7d4-9ebd28987951.png)

* components/angular-sanitize/angular-sanitize.js

```script.js
var myApp = angular.module('MyApp', ['onsen', 'ui.router', 'ngSanitize']);
```

# angular-swipeの導入

詳細画面では、左右スワイプで表示情報の変更を行いたいため、スワイプ用モジュールを導入します。

![swipe01.png](https://qiita-image-store.s3.amazonaws.com/0/184714/0e2d7152-ad15-5e4c-7c44-9e5e746fb59d.png)

![swipe02.png](https://qiita-image-store.s3.amazonaws.com/0/184714/3b267ea1-5fbe-0323-4ca0-7f8b573fbb78.png)

![swipe03.png](https://qiita-image-store.s3.amazonaws.com/0/184714/3b633ea4-a944-dfad-0948-6e19c4ca16d7.png)

* components/angular-swipe/dist/angular-swipe.js

```script.js
var myApp = angular.module('MyApp', ['onsen', 'ui.router', 'ngSanitize', 'swipe']);
```

# angular-animateの導入

スワイプ処理時に、左右に動くアニメーションを入れたいので、アニメーション用モジュールを導入します。

![animate01.png](https://qiita-image-store.s3.amazonaws.com/0/184714/baaece82-6b97-fc4e-81e0-d186495cc4b5.png)

![animate02.png](https://qiita-image-store.s3.amazonaws.com/0/184714/7d32b5e8-e3b3-2dc0-db40-4b3150833470.png)

* 2017/09/22時点での導入可能最新バージョンは、1.6.6です
* buildを含むバージョンは導入できません。

![animate03.png](https://qiita-image-store.s3.amazonaws.com/0/184714/db5d0e96-999b-3837-cb56-1813a8d9e156.png)

* components/angular-animate/angular-animate.js

```script.js
var myApp = angular.module('MyApp', ['onsen', 'ui.router', 'ngSanitize', 'swipe', 'ngAnimate']);
```

# animate.cssの導入

簡単にCSSアニメーションを導入するため、animate.cssを導入します。
参考）[animate.css](https://daneden.github.io/animate.css/)

![animate04.png](https://qiita-image-store.s3.amazonaws.com/0/184714/90565571-5962-6e24-69b4-d0ddf56d9aa8.png)

![animate05.png](https://qiita-image-store.s3.amazonaws.com/0/184714/2843ff73-9ba0-e098-1a15-a38533be57f4.png)

![animate06.png](https://qiita-image-store.s3.amazonaws.com/0/184714/54731d3e-f644-370a-7be2-8ae2c52d6601.png)

* components/animate.css/animate.css

# html

```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="script.js"></script>

  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="css/style.css">
</head>
<body ng-app="MyApp">

	<ons-page>
        <!-- ツールバー -->
		<ons-toolbar>
			<div class="center">スワイプ処理</div>
		</ons-toolbar>
		
        <!-- 画面のメイン部分 -->
		<div ng-controller="JSONController">
			<ons-button ng-click="readJSON();">JSON読み込み</ons-button>
		</div>
		
        <!-- 遷移読込部分 -->
		<div style="padding: 20px 10px;" ui-view></div>
		
        <!-- ローディング読込用ディレクティブ -->
		<my-loader></my-loader>

	</ons-page>
	
	<!-- リスト画面 -->
	<ons-template id="list.html">
		<h1>Flower List</h1>
		<div ng-controller="ListController">
			<!-- リスト繰り返し -->
			<h2 ng-repeat="(i, item) in list" ng-click="jumpDetail(i)">
				<!-- 各名称からリンク(引数にindexをつける) -->
				{{i}} : {{item.name}}
			</h2>
		</div>
	</ons-template>
	
	<!-- 詳細画面 -->
	<ons-template id="detail.html">
		<!-- 先頭にジャンプするアンカー -->
		<a id="top"></a>
		<h1>Flower Detail</h1>
		<!-- コントローラとスワイプ属性 -->
		<div ng-controller="DetailController" ng-swipe-left="next();" ng-swipe-right="prev();">
			<!-- リスト繰り返し -->
			<div ng-repeat="(i, item) in list">
				<!-- 表示対象indexである場合のみ、表示-->
			  	<div ng-show="isCurrent(i)" class="slide {{direction}}">
			  		<!-- 名称 -->
			  		<h2>{{item.name}}</h2>
			  		<!-- 解説(HTMLバインドをする) -->
					<div class="padding" ng-bind-html="item.comment">
					</div>
					<!-- ページナビゲーション -->
					<div class="navi-bottom">
						<!-- 前に遷移 -->
						<span class="navi-left" ng-click="prev();">
							<ons-icon icon="fa-angle-left" size="2x"></ons-icon>
							<span class="navi-text">{{prevName();}}</span>
						</span>
						<!-- 上に遷移 -->
						<span class="navi-center navi-text" ng-click="top();">
							{{item.name}}
						</span>
						<!-- 次に遷移 -->
						<span class="navi-right" ng-click="next();">
							<span class="navi-text">{{nextName();}}</span>
							<ons-icon icon="fa-angle-right" size="2x"></ons-icon>
						</span>
					</div>
			  	</div>
			</div>
		</div>
	</ons-template>
	
    <!-- ローディング画面 -->
	<ons-template id="loader.html">
		<div ng-if="$root.isLoading" class="loader-parent"><div class="loader">Loading...</div></div>
	</ons-template>
</body>	
</html>
```

# json

```flower.json
{
	"list": [
		{
			"name": "桜",
			"comment": "サクラ（桜）は、バラ科モモ亜科スモモ属 (Prunus, Cerasus) の落葉樹の総称。 <br>サクラは日本文化に馴染みの深い植物である(サクラ#日本人とサクラ)。 また、日本において観賞用として植えられているサクラの多くはソメイヨシノという品種である。"
		},
		{
			"name": "桃",
			"comment": "春には五弁または多重弁の花を咲かせ、夏には水分が多く甘い球形の果実を実らせる。<br>中国原産。食用・観賞用として世界各地で栽培されている。未成熟な果実や種子にはアミグダリンという青酸配糖体が含まれる。"
		},
		{
			"name": "梅",
			"comment" : "<h2>概要</h2><p>ウメ（梅、学名：Prunus mume、英: Japanese apricot[1]）は、バラ科サクラ属の落葉高木、またはその果実のこと。<br>花芽はモモと異なり、一節につき1個となるため、モモに比べ、開花時の華やかな印象は薄い。<br>毎年2月から4月に5枚の花弁のある1センチメートルから3センチメートルほどの花を葉に先立って咲かせる。<br>花の色は白、またはピンクから赤。葉は互生で先がとがった卵形で、周囲が鋸歯状。樹木と花は主に鑑賞用、実は食用とされる。</p><h2>分類</h2><p>梅には500種以上の品種があると言われている。近縁のアンズ、スモモと複雑に交雑している為、主に花梅を園芸上は諸説の分類があり、実梅も同じ種であるので同様に分類できるが[2]、実梅の分類は一般には用いられない[3]。梅は、野梅系、緋梅（紅梅[4]）系、豊後系に大きく3系統に分類できる[5]。</p><h2>果実</h2><p>果実は、2センチメートルから3センチメートルのほぼ球形の核果で、実の片側に浅い溝がある。6月頃に黄色く熟す。七十二候の芒種末候には、「梅子黄（梅の実が黄ばんで熟す）」とある。特定の地域のみで栽培される地方品種が多く、国内どこでも入手可能な品種は比較的限定される。又、品種によっては花粉が無かったり自家受粉しない品種もあり、その場合は開花時期が重なるように授粉用の品種も必要となる。</p><h2>薬効と毒性</h2><p>果実を梅干し、梅酒、梅酢、梅醤やジャムなどにして食用とする。また甘露梅やのし梅などの菓子や、梅肉煮などの料理にも用いられる。強い酸味が特徴であり、クエン酸をはじめとする有機酸などを多く含むので健康食品としても販売されている。果実から種を取り出すための専用器具も販売されている。 また、果実だけでなく食べた後の種核、俗にいう天神様も食用にでき、梅茶漬けにアクセントとして添える。等の利用法がある。<br>中国では紀元前から酸味料として用いられており、塩とともに最古の調味料だとされている。日本語でも使われるよい味加減や調整を意味する単語「塩梅（あんばい）」とは、元々はウメと塩による味付けがうまくいったことを示した言葉である。また、話梅（広東語: ワームイ）と呼ばれる干して甘味を付けた梅が菓子として売られており、近年では日本にも広まっている。<br>さらに漢方薬の「烏梅（うばい）」は藁や草を燃やす煙で真っ黒にいぶしたウメの実で、健胃、整腸、駆虫、止血、強心作用があるとされるほか、「グラム陽性菌、グラム陰性の腸内細菌、各種真菌に対し試験管内で顕著な抑制効果あり」との報告がある[8]。<br>なお、サッポロ飲料株式会社・近畿大学生物理工学部・和歌山県工業技術センターの共同研究で、梅の果実成分による疲労軽減効果が実証されている[9]。<br>6か月の梅酒の飲用で、HDLコレステロールが有意に増加し、動脈硬化指数が有意に低下し、血圧が低下傾向となり、血糖値は変化が認められなかった、との報告がある[10]。</p>"
		}
	]
}
```

# javascript

```script.js
var myApp = angular.module('MyApp', ['onsen', 'ui.router', 'ngSanitize', 'swipe', 'ngAnimate']);

// 遷移処理
myApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

		$stateProvider
			// リスト画面遷移
			.state('list', {
				url: '/list',
				templateUrl: 'list.html'
			})
			// 詳細画面遷移
			.state('detail', {
				url: '/detail',
				templateUrl: 'detail.html',
				// 引数を受け付ける
				params: {
					"index": null,
					"list": null
				}
			})
			
	}]);

// メイン画面用コントローラ
myApp.controller('JSONController', ['$scope', '$state', '$rootScope', '$timeout', function($scope, $state, $rootScope, $timeout) {
		$scope.readJSON = function() {
	     	console.log("readJSON");
	     	
			// ローディングフラグON
			$rootScope.isLoading = true;
			
			// 1秒待ってから遷移する
			$timeout(function() {
				$state.go('list');
			}, 1000);
		}
	}]);

// リスト画面用コントローラ
myApp.controller('ListController', ['$scope', '$state', '$rootScope', 'JsonFlowerService', function($scope, $state, $rootScope, JsonFlowerService) {
		// Jsonデータ取得
		JsonFlowerService.run().then(
			function(resultList) {
				// 結果リストが取れたら、スコープに設定
				$scope.list = resultList;
			}, function(response) {
				ons.notification.alert({
					title: 'JSON取得失敗',
					message: response
				});
			}
		);
		
		// 名称リンク押下
		$scope.jumpDetail = function(idx) {
			// indexとリストを引数にして、詳細画面を表示する
			$state.go('detail', {'index': idx, 'list': $scope.list});
		}
	}]);

// 詳細画面用コントローラ
myApp.controller('DetailController', ['$scope', '$state', '$stateParams', '$location', '$anchorScroll', function($scope, $state, $stateParams, $location, $anchorScroll) {		
		
		// 引き継がれたリストをスコープに設定
		$scope.list = $stateParams.list;
		// 引き継がれたindexを現在の表示対象に設定
		$scope.currentIndex = $stateParams.index;
		// アニメーション方向
		$scope.direction = 'left';
		
		// 現在の表示対象であるか
		$scope.isCurrent = function (index) {
			return $scope.currentIndex === index;
		};
		
		// 次に遷移する
		$scope.next = function () {
			console.log("next currentIndex: "+ $scope.currentIndex);
			$scope.direction = 'left';
			$scope.currentIndex = $scope.currentIndex < $scope.list.length-1 ? ++$scope.currentIndex : 0;
			console.log("** next currentIndex: "+ $scope.currentIndex);
		};
		
		// 前に遷移する
		$scope.prev = function () {
			console.log("prev currentIndex: "+ $scope.currentIndex);
			$scope.direction = 'right';
			$scope.currentIndex = $scope.currentIndex > 0 ? --$scope.currentIndex : $scope.list.length-1;
			console.log("** prev currentIndex: "+ $scope.currentIndex);
		};
		
		$scope.top = function () {
			// 最上部遷移
			$location.hash('top');
			$anchorScroll();
		}
		
		// ひとつ前の名称
		$scope.prevName = function() {
			var idx = $scope.currentIndex > 0 ? $scope.currentIndex -1 : $scope.list.length-1;
			return $scope.list[idx].name;
		}
		
		// ひとつ次の名称
		$scope.nextName = function() {
			var idx = $scope.currentIndex < $scope.list.length-1 ? $scope.currentIndex + 1 : 0;
			return $scope.list[idx].name;
		}
				
		
	}]);




// ローディングタグ
myApp.directive('myLoader', function() {
		return {
			restrict : 'E',
			replace: true,
			templateUrl: "loader.html"
		};
	});	
	
	
// 画面遷移タイミング処理
myApp.run(['$rootScope', '$transitions', '$state', function($rootScope, $transitions, $state){
	$transitions.onSuccess({to:'*'}, function(trans){
		// ページ読み込み成功
		
		// ローディングフラグOFF
		$rootScope.isLoading = false;
	});
	
}]);
		

// JSON読込サービス
myApp.service('JsonFlowerService', ['$q', '$timeout', '$http', function($q, $timeout, $http){
     this.run = function () {
     	console.log("JsonFlowerService");
     	
		var deferred = $q.defer();
		
		$timeout(function(){
			$http({
				method: 'GET',
				url: 'flower.json'
			}).then(function successCallback(response) {				
				// 成功した場合、リストをまるごと返す
				deferred.resolve(response.data.list);
			}, function errorCallback(response) {
				// 失敗した場合
				var msg = "JsonFlowerService json取得失敗: "+ response.status;
				console.error(msg);
				deferred.reject(msg);
			});
		});
		
		return deferred.promise;
    };

}]);
        		
```
# css

```style.css
/* --------------------- ローディング ------------------------------- */

div.loader-parent {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	margin: auto;
	height: 200px;
	width: 200px;
}
.loader {
  margin: 80px auto;
  font-size: 25px;
  width: 1em;
  height: 1em;
  border-radius: 50%;
  position: relative;
  text-indent: -9999em;
  -webkit-animation: load5 1.1s infinite ease;
  animation: load5 1.1s infinite ease;
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  transform: translateZ(0);
}
@-webkit-keyframes load5 {
  0%,
  100% {
    box-shadow: 0em -2.6em 0em 0em #7f7f7f, 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.5), -1.8em -1.8em 0 0em rgba(127,127,127, 0.7);
  }
  12.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.7), 1.8em -1.8em 0 0em #7f7f7f, 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.5);
  }
  25% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.5), 1.8em -1.8em 0 0em rgba(127,127,127, 0.7), 2.5em 0em 0 0em #7f7f7f, 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  37.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.5), 2.5em 0em 0 0em rgba(127,127,127, 0.7), 1.75em 1.75em 0 0em #7f7f7f, 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  50% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.5), 1.75em 1.75em 0 0em rgba(127,127,127, 0.7), 0em 2.5em 0 0em #7f7f7f, -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  62.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.5), 0em 2.5em 0 0em rgba(127,127,127, 0.7), -1.8em 1.8em 0 0em #7f7f7f, -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  75% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.5), -1.8em 1.8em 0 0em rgba(127,127,127, 0.7), -2.6em 0em 0 0em #7f7f7f, -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  87.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.5), -2.6em 0em 0 0em rgba(127,127,127, 0.7), -1.8em -1.8em 0 0em #7f7f7f;
  }
}
@keyframes load5 {
  0%,
  100% {
    box-shadow: 0em -2.6em 0em 0em #7f7f7f, 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.5), -1.8em -1.8em 0 0em rgba(127,127,127, 0.7);
  }
  12.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.7), 1.8em -1.8em 0 0em #7f7f7f, 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.5);
  }
  25% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.5), 1.8em -1.8em 0 0em rgba(127,127,127, 0.7), 2.5em 0em 0 0em #7f7f7f, 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  37.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.5), 2.5em 0em 0 0em rgba(127,127,127, 0.7), 1.75em 1.75em 0 0em #7f7f7f, 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  50% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.5), 1.75em 1.75em 0 0em rgba(127,127,127, 0.7), 0em 2.5em 0 0em #7f7f7f, -1.8em 1.8em 0 0em rgba(127,127,127, 0.2), -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  62.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.5), 0em 2.5em 0 0em rgba(127,127,127, 0.7), -1.8em 1.8em 0 0em #7f7f7f, -2.6em 0em 0 0em rgba(127,127,127, 0.2), -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  75% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.5), -1.8em 1.8em 0 0em rgba(127,127,127, 0.7), -2.6em 0em 0 0em #7f7f7f, -1.8em -1.8em 0 0em rgba(127,127,127, 0.2);
  }
  87.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(127,127,127, 0.2), 1.8em -1.8em 0 0em rgba(127,127,127, 0.2), 2.5em 0em 0 0em rgba(127,127,127, 0.2), 1.75em 1.75em 0 0em rgba(127,127,127, 0.2), 0em 2.5em 0 0em rgba(127,127,127, 0.2), -1.8em 1.8em 0 0em rgba(127,127,127, 0.5), -2.6em 0em 0 0em rgba(127,127,127, 0.7), -1.8em -1.8em 0 0em #7f7f7f;
  }
}



/* ------------------- アニメーション ------------------------ */

/* スワイプ */
.slide.left.ng-hide-remove {
	animation: slideInRight 0.8s ease 0s 1 normal;
	-webkit-animation: slideInRight 0.8s ease 0s 1 normal;
	display: block!important;
}

.slide.right.ng-hide-remove {
	animation: slideInLeft 0.8s ease 0s 1 normal;
	-webkit-animation: slideInLeft 0.8s ease 0s 1 normal;
	display: block!important;
}


/* ------------------- ナビゲーション ------------------------ */

.navi-bottom {
	text-align: center;
	padding-top: 20px;
	padding-bottom: 40px;
	width: 100%;
}

.navi-left {
	text-align: left;
	margin-right: 20px;
}

.navi-right {
	text-align: right;
	margin-left: 20px;
}

.navi-center {
	text-align: center;
}

.navi-text {
	color: #555555;
	font-size: 24px;
	font-weight: bold;
	vertical-align: text-bottom;
}

```

# 処理の流れ

※リスト画面表示までは割愛

1. 名称押下
    2. 押下されたindexを引数に、```jumpDetail```が実行される
    3. indexとリストを引数にして、```detail```に遷移する
4. ```state=detail```を実行
    5. ```index```と```list```を次画面に引き継ぐ
4. ```detail.html```表示
    5. ```$stateParams```から引き継がれた```list```を取得し、```$scope```に設定
    5. ```$stateParams```から引き継がれた```index```を取得し、```$scope```に設定
    6. ```list```を繰り返し表示する(```ng-repeat```)
    7. ```isCurrent```で```index```が合致した項目のみ表示する(```ng-show```)
    8. ```item.comment```を```ng-bind-html```で、HTMLタグを有効にして出力
9. 右にスワイプした場合、もしくは、＞を押下した場合
    10. ```next```を実行
        11. アニメーションの方向属性を```left```に設定
        12. 表示対象indexをインクリメント（最後を表示していた場合、0番目を表示）
    13. 表示対象indexが切り替わり、```ng-show```の要素が非表示に代わり(```ng-hide```)、非表示であった項目が表示されるタイミングで、css: ```.slide.left.ng-hide-remove```が実行される
9. 左にスワイプした場合、もしくは、＜を押下した場合
    10. ```next```を実行
        11. アニメーションの方向属性を```right```に設定
        12. 表示対象indexをデクリメント（最初を表示していた場合、最後要素を表示）
    13. 表示対象indexが切り替わり、```ng-show```の要素が非表示に代わり(```ng-hide```)、非表示であった項目が表示されるタイミングで、css: ```.slide.right.ng-hide-remove```が実行される
14. 画面下部の現在表示している名称を押下した場合
    15. ```top```を実行
        16. ```$location.hash('top');```で```id=top```の場所を取得する
        17. ```$anchorScroll```で、```<a id="top"></a>```に飛ぶ
        17. ※プレビューモードでこの処理を実行した場合、```ons-toolbar```タグの内容が消える事があります。実機デバッグ、またビルドアプリを実機で実行した場合には、消えません。

参考）
[AngularJSのアニメーションの仕組みについて](http://js.studio-kingdom.com/angularjs/tips/how_to_animation)
[AngularJSでちゃちゃっとアニメーションを試す](http://angularjsninja.com/blog/2013/12/08/angularjs-nganimate/)
[Angular Simple Slider directive](http://embed.plnkr.co/SiVmTy/)

# ソースコード

https://github.com/miz21358/ui-router-swipe-sample