この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
スマートフォンのタッチイベントを用いて、画像を横方向にスライドさせる実装をご紹介します。
※PCではマウスイベントで代用可能だと思われます。
※Android/iPhone両方で動作するはずです。
ポイントとしては、スワイプとフリックの動作です。
スワイプ
画面をタッチした状態で指を動かす動作
フリック
画面をタッチした状態で指を「素早く動かす、弾く」動作
この2つの動作を組み込むことで、ネイティブアプリのようなスムーズな動きが実現できます。
■ sample.css
body {margin:0;padding:0;}
#slider {
position: relative;
width: 320px;
}
#slider a:focus {
outline: 0;
}
.slider-view {
position: relative;
border: 1px solid #bbb;
width: 320px; /* スライダーで表示するエリアの大きさ */
height: 360px;
overflow: hidden; /* 必須 */
}
.slider-container {
position: absolute;
top: 0;
left: 0;
background-color: black;
width: 2000px; /* 本来はコンテンツの横幅を取得して動的に設定すべきです */
}
/* スライドするコンテンツ部分 */
.slider-container div {
position: relative; /* ループ処理に使う */
float: left;
}
/* チラツキ対策 */
.slider-container {
-webkit-transform:translate3d(0,0,0);
}
■ sample.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<title>Sample</title>
<script src="/assets/jquery.js" type="text/javascript"></script>
<script src="/assets/sample.js" type="text/javascript"></script>
<link href="/assets/sample.css" media="screen" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="slider">
<div class="slider-view">
<div class="slider-container">
<div id=1><img src="/images/01.jpg" /></div>
<div id=2><img src="/images/02.jpg" /></div>
<div id=3><img src="/images/03.jpg" /></div>
</di>
</div>
</div>
</body>
</html>
sample.jsではjQueryを利用しているので、jQueryをロードしておきます。
※HTMLタグは都合上全角になっております。実際は半角です。
■ sample.js
$(function () {
// 対象となる要素を変数に格納しておく
var $slider = $('#slider'),
$container = $slider.find('div.slider-container'),
$containerDiv = $slider.find('div.slider-container div');
var distance = 0; //移動距離を指定するのに使う
// スライド関数
var slide = {
// スライド(進む)
next: function (index, spd, flick_flg) {
distance = distance + index;
slide.scroll(distance, spd, flick_flg);
},
// スライド(戻る)
prev: function (index, spd, flick_flg) {
distance = distance - index;
slide.scroll(distance, spd, flick_flg);
},
//移動距離分スクロール
scroll : function (d, spd, flick_flg) {
var move = -d
var env = 'translate3d(' + move + 'px,0,0)';
if (flick_flg) {
/* フリック時はwebkit-transformプロパティを設定し、滑らかなアニメーションにする */
transit_property = '-webkit-transform ' + spd + 'ms cubic-bezier(0,0,0.25,1)';
} else {
transit_property = 'none';
}
$container.css({
'-webkit-transform':env,
'-webkit-transition':transit_property
}).bind('webkitTransitionEnd', function(){
//ここで移動後の終了イベントが取れます
});
}
}
$(window).load(function() {
var pageX; //リアルタイムのX座標
var pageY; //リアルタイムのY座標
var startPageX; //スタート時のX 座標の位置
var startTime; //スタート時の時間
var move_time = 0;
/* タッチの開始時のイベント */
$('#slider').bind('touchstart', function() {
event.preventDefault(); // ページが動いたり、反応を止める(A タグなど)
pageX = event.changedTouches[0].pageX;
pageY = event.changedTouches[0].pageY;
startPageX = pageX;
startTime = +new Date();
});
/* タッチしたまま動かしたときのイベント */
$('#slider').bind('touchmove', function() {
var moveX = event.changedTouches[0].pageX; // X 座標の位置
var absX = Math.abs(pageX - moveX); // 移動距離の絶対値
var spd = 0.5;
pageY = event.changedTouches[0].pageY;
/* スワイプ処理 */
if (pageX > moveX) {
slide.next(absX, spd);
} else if (pageX < moveX) {
slide.prev(absX, spd);
}
pageX = moveX;
});
/* タッチ状態から離れたときのイベント */
$('#slider').bind('touchend', function() {
/* 終了処理が必要ならここに書く */
/* このイベントは、位置を取得できないので注意 */
var diffX = startPageX - pageX;
var absX = Math.abs(diffX);
var mv = 200; //フリック移動距離
var spd = 700; //フリックスピード
var now = +new Date(); //現在時間
var diffTime = now - startTime; //touchstartからの経過時間
/* フリック処理(touchstartからの経過時間が短い場合) */
if (diffTime < 400) {
if (diffX > 0) {
slide.next(mv, spd, true);
} else if (diffX < 0) {
slide.prev(mv, spd, true);
}
}
move_time = 0;
});
});
});
スワイプかフリックかの判定は、touchstart(タッチした瞬間)からtouchend(離した瞬間)までの時間で判定します。
上記サンプルでは400ミリ秒未満の場合はフリックと判定するようにしています(diffTime < 400)
以上です。スワイプとフリックでネイティブアプリのような動きを実現しましょう!