前回に引き続き、今回も 3D Touch ネタをお届けしようかと思います。
いくつかの無視できない新機能を試す為に、わざわざ iPhone 6s(ローズゴールド)を買った訳ですからね。
使い倒さなきゃ、もったいないってぇモンですよ!(貧乏人根性)
ところで、iPhone 6s のサイズ感は、やっぱりいいですね。手の平に収まる感じは 4 インチ時代とあまり変わらないのに、ディスプレイは確実に大きくなっている。
対して、Plus はダメです。デカ過ぎます。6 Plus を 1 年使い続けましたが、とうとう大きさに慣れることはありませんでした。すげー邪魔くさかった。
6s に SIM を乗せ換えることができて、本当にホッとしています。
さてさて、そんな雑談はさておき、今回は iPhone 6s (Plus) 上で動作する iOS 9 の Safari で、3D Touch を使う方法を見ていきましょう。
正直、いまのところは非常にニッチで、しかも今後は扱い方が変わっていくと思われますので、ほとんど実用性はないですけどね。
まぁ、いつものように、万が一どなたかのお役に立ちましたら。
読み込み中です。少々お待ち下さい
Safari で 3D Touch
まずは、Safari 上における 3D Touch がどんな感覚かを、軽く試して慣れていただこうかと。
iPhone 6s (Plus) の Safari でご覧の方は、下の囲いをぐっと押してみてください(できれば、試しに 100% まで押し込んでみてください)。
この囲いの中をぐぐっと押すと
強弱に応じてバーが伸び縮みします
上手く反応しない場合は
指を左右に傾けてください
手元に無いので確認できませんが、Force Touch 対応の TrackPad を搭載した新しい MacBook でも、もしかしたら反応するかも知れません。あ、あと、Apple から新しい Magic TrackPad が発売されたら、MacBook 以外の Mac でも使えるようになるかも知れませんね。
2015/10/14 追記:
発売されましたが、超高い。買おうかどうしようか迷い中です。
それ以外の機器では、残念ながらいまのところ(2015/10時点)反応しないかと思われます。
2015/10/08 追記:
と思ったら、あれぇ、Nexus 7 2013(Android 5.1.1)の Chrome(45.0.2454.94)や Firefox(41.0)でも、なんか反応しますねぇ。しかも、何故か 121% まで伸びてしまいます。
ていうか、強弱も判別できてるみたいなんですけど、どうやってんの、コレ。接地面積?
ちなみに、Android 4.2.2 の別端末だと反応しませんでした。
ただし、PC でも Chrome のデベロッパーツールでモバイル端末をエミュレートすると、動作を確認できるみたいです。なんか、マウスでも動作するのでビックリ。Chrome すげぇな。
2015/10/08 追記:
と、一瞬 Chrome に感心しかけたのですが、ジツはあんまり凄くなかった。モバイル端末をエミュレートした場合、常に TouchEvent.force に 1 が設定されてるだけだ、これ。
つまり、3D Touch 非対応の iPhone 5 だろうが Nexus 5 を選択しようが、常に 1 っぽい。かえって処置に困るので、修正してくんないかなぁ。
いやぁ、これは他にも、予想外の動作をする環境がありそうですねぇ。
もう少し、それっぽく
100% にするには、どのくらいの感覚で押し込めば良いのか、なんとなくお分かりいただけたでしょうか。
そしたら次は、このページ内のどこでも良いので、「リンクおよび画像以外」の地の文の部分で、ぐっと画面を押し込んでみてください。
迷った場合は、ここでも構いません。
どうでしょう。
以下の画像のようなメニューが、きちんと表示されたでしょうか。
(ジツは、今回は 100% まで押し込まずとも、80% でメニューが表示されるように調整しています。だって、あんまり強く押すの、疲れるじゃないですか......)
ホーム画面で対応アプリのアイコンをぐっと押し込んだ際に表示されるメニューを模して、なんとなくそれっぽく作ってみました。
いちおう、各アイテムとも機能します。何も選択せずにキャンセルする場合は、メニュー以外のどこかをタップしてください。
いや、ホントはもっと面白い使い途があると思うんですが、パッと思い付かなかったんですよー。目新しさがなくて申し訳ないです。
2015/10/08 追記:
簡単に対処しましたが、いくつかの Android 端末では、ちょっと押し込んだだけでメニューが表示されてしまう場合があります。
なんか面白いのでこのままにしておきますが、Android 端末でスクロールする時は優しく撫でていただけると助かります。
あと、Android だとブラーが異常に重いみたいなので切っておきました。ですので、Android 端末でメニューを表示した場合、ぼかしが入りません。
ほんのり技術的な話
ここからは、ほのかに技術的な話をしていきましょう。
とは言い条、大して語るべきこともないのですが、今回の実装ではマウスイベントの Touch.force を利用しました。
Touch Events - Level 2 のドラフトで追加されたみたいです。
ざっくり言うと、タッチの強弱次第で 0 から 1 までの値を取る Touch.force を、主に touchmove で処理しているだけです。
良くある書き方で簡単に書くと、こんな感じでしょうか。
document.body.addEventListener("touchmove", function(e) { console.log("js force - " + e.touches[0].force); });
$("body").on("touchmove", function(e) { console.log("jq force - " + e.originalEvent.touches[0].force); });
ここまでくれば、後はお好きに実装するだけです。
必要であれば touchstart で初期処理、touchend で後処理を行うと良いでしょう。
というか、iOS 9 の Safari は (webkit)mouseforcewillbegin, mouseforcedown, mouseforceup, mouseforcechange という Force Touch API に対応して、これらのリスナでイベント処理を行えるような話だったらしいのですが(強弱は MouseEvent の webkitForce で取得する模様)、2015/10 時点では、コレ、多分 iOS 9.0.2 の Safari に実装されてないですよね?
私が何かを勘違いしていたら大変申し訳ないのですが、少なくともこちらで試した範囲では、ウンともスンともしませんでした。
良く見ると Touch ではなく Mouse イベントである上に、Force Touch API という呼称からして、ジツは新しい MacBook の Safari だったら対応していたりするんでしょうか。
もしくは、まだ一部の開発版でしか実装されてないとか?
まー、なんか良く分からんので、詳しくは以下の記事等をご参照ください(丸投げ)。
問題点
今回、実装する上で気が付いた、問題になりそうな点について、いくつか触れておきます。
文字が選択されてしまう
まず、何も対策を施さないと、深押しを処理しようとした時に、タイミング次第でページ上の文字が選択されてしまうことがあります。
実用上は特に問題無いのですが、「コピー|辞書|...」みたいなメニューや拡大鏡まで表示されて、見た目がみっともないので、なんとか対処したいところです。
ところが、iOS の Safari は、既に文字が選択されている状態だと、何故か window.getSelection().removeAllRanges() や window.getSelection().empty() で文字の選択を解除できません(エラーも発生しない)。createRange で適当な空文字を選択しようと試みてもダメでした。
試した限りでは、document.execCommand("Unselect") も機能しません。古の document.selection は、そもそも対応していません。
ですので、3D Touch 時にどうしても文字が選択されて欲しくない場合は、スタイルシートで user-select に none を指定することで、文書全体をそもそも選択不可にするしかないかも知れません。
今回は、その方法で対応しました。つまり、上掲のサンプルコード部分以外では、テキストを選択できなくなっています、すみません。
お手数ですが、テキスト選択の可不可を切り替えたい場合は、以下のボタンをタップしてください(ついでに、ピンチも制限しましたので、ページをズームしたい場合は、下のボタンを押して「テキスト選択可能」な状態に切り替えてください)。
ちなみに、メニューを表示する時に user-select に none を設定して、メニューの非表示で all に戻すような処理も試してみたのですが、既に文字が選択された状態だと、どうやっても解除されませんでした。setTimeout による時間差とかも試してみたんですけどねぇ。うーん......
試してませんが、あとパッと思いつくのは、タップイベントを自分で発火しちゃうか、それでもなければメニューのウラにテキストボックスを隠して、表示する時にそこにフォーカスを当てるとか。いやぁ、外法ですねぇ(笑)
ただ、今回の私が気付かなかっただけで、もっとよい解決方法があるんじゃないかと思いますので、その辺りの工夫は皆様にお任せします(丸投げ)。
vibrate が効かない
3D Touch って、押し込んだ時の「ブルッ」っていうフィードバックが重要じゃないですか?
嗚呼、自分は確かに深押しすることが出来たのだナァ、みたいな(大袈裟)
それを擬似的に再現しようと思いまして、JavaScript で vibrate を呼ぼうとしたのですが、iOS の Safari では何故か全く機能しないようです(例によって未実装などのエラーは発生しない)。
navigator.vibrate でも navigator.webkitVibrate でも震えてくれませんでした。どうやら、誰にも会いたくないようです。
なので、今回は残念ながら、「ブルッ」というフィードバックは見送りました。無念。
画像の拡大やリンク先のチラ見せとの相性
iOS 9 ネイティブの挙動として、Safari 上で画像やリンクを深押しすると、拡大や「先読みチラ見せ」をしてくれたり(Peek)、さらに押し続けるとその対象に遷移する(Pop)という機能があります(詳しくは、本家の紹介ページを参照)。
今回のように、深押しでメニューを表示するような実装の場合、この Peek や Pop と相性が悪いので、タッチした対象が画像やリンクだったら処理しない、等の判断を入れた方が良いと思います。
ちなみに、画像やリンクの親をタッチした場合でも Peek や Pop が実行される場合があるようなので、当初は簡単に対応していたのですが、あまり精度が上がらなかったので削除しました。
touchmove は無理がある
今回は、touchmove で 3D Touch を処理した訳ですが、なにしろ touchmove ですので、深押しの度合いが変わったとしても、指が動いてなければ、イベントが飛んで来ないようです。
とはいえ、ギュッと画面を押し込むと、ほとんどの場合は指がわずかに動いて touchmove イベントが発生するので致命的とまでは言いませんが、割りとコツを必要とする操作感になってしまいがちだと思います。
このような理由から、冒頭のお試しサンプル枠では「上手く反応しない場合は指を左右に傾けてください」と書いた訳ですが、各ブラウザにまともな Force(3D) Touch API が実装されるか、もしくは force の値が変わっただけでイベントが飛んでくるようになれば、そんなことをいちいち気にしないでも、ちゃんと処理できるようになると思います。
Android の対応が中途半端
上でいくつか追記しましたが、Nexus 7 2013 等の Android 端末で TouchEvent.force が設定される場合があるようです。
しかも、なぜか 0 ~ 1.20960000909805298 が設定されるみたい。上で触れた Touch Events - Level 2 のドラフトだけでなく、MDN の Touch.force でも、"This is a value between 0.0 (no pressure) and 1.0 (the maximum amount of pressure the hardware can recognize)." と書いてあるのですが......まぁ、そのウチ修正されるでしょう。
そもそも、ディスプレイ自体が Force Touch ライクな機能に対応していない筈の Nexus 7 2013 で反応したのが不思議な訳でして、なんかの手違いで値が設定されちゃってるだけなんですかね?
それとも、最近の Android(4.2.2 の端末だと反応しなかったので、5 以降くらい?)は、密かに OS レベルでタッチの強弱を接地面積かなんかから判断するようになったとか? そんな話、ありましたっけ? 非公開?
まぁ、そんな訳で、どの端末でもという訳じゃないと思いますが、Android でも 3D Touch ライクな体験ができるみたいですよ(笑)
例によって、OS 毎に微妙に挙動が異なるのが、頭イタイところですが......う~ん、やっぱり、3D Touch は TouchEvent.force ではなく、mouseforce 系のリスナで処理するのが筋ってことなんですかねぇ。まだ動かないっぽいけど。
2015/10/14 追記
画面に軽く触れた指を傾けるだけで、力を入れなくても反応するし、上で記述している Nexus 7 の感圧タッチもどきは、やっぱり接地面積っぽいなぁ。
(ちなみに、感圧タッチに真っ当に対応している iPhone 6s の場合は、当たり前ですが画面に触れた指を傾けても、そこからさらに力を込めない限り深く押されたとは認識されません)
Nexus 7 2013 は抵抗膜方式ではなく静電容量方式なので、同じ指が触れ続けていることを前提とした移動距離を接地面積とすることで、仮想的に強弱を判定してるとか?
そもそも、なんで現時点(2015/10)の Android で反応するのだ。
2015/09/07 に上梓されたと思しいこちらの記事でも、「ただし、感圧タッチのユーザインターフェイスは、Android OSでは正式にサポートされていません」て書いてあるんだけどなぁ。
上に書いたように Firefox でも動作するので、Chrome が独自にやらかした実装したって訳でもなさそうです。
どころか、いま適当に WebView 使うアプリを作って Nexus 7 2013 で試してみたら、やっぱり同じように反応しましたし。
不思議ふしぎ。なんか、Android をバージョンアップしたら、しれっと値(TouchEvent.force)が設定されなくなってそう(笑)
ていうか、私が寡聞にして知らなかっただけで、これ、割りと知られてる機能なんですかね?
ていうか、この件に関しては、別記事として切り出せば良かったのでは......(ボソッ)
いや、でも、切り出そうにも現時点で掴んでいることが曖昧過ぎて、記事にできないというか。
おわりに
いやー、とりあえず記事にしてはみましたが、まだ対応している端末も少ないですし(実質、一部の Apple 製品だけですよね?)、今後 API も整備&変更されていくと思われますし、ジッサイのトコロ、3D Touch を利用した機能を Web サイトに本格的に実装するのは、あまりにも時期尚早であろうかと思います。
そんな訳で、もちろんライブラリ化するつもりもありません。
つまり、これって単なるネタ記事ということですね。
しかも、すぐ情報が古くなって風化しそうだなぁ......うぅん。
まぁ、いっか(笑)
2015/10/08 追記
タイムリーに、こんな記事が。
Force(3D) Touch は、案外と当たり前の機能になっていくのかも知れませんね。
ていうか、Android でも、既に似たようなタッチの強弱感知を備えた Huawei Mate S という機種が発表されてたんですね。
日本でも発売されるみたいです......が、10 万もするのか。高ぇー(笑)
2015/10/10 追記
あと、こんな記事も。
2年後には使い方も洗練されて、普通の機能になってるかも。
2015/10/14 追記
Apple から、Force Touch に対応した新しい Magic Trackpad が発売されましたね!
割りと楽しみにしてたので、早速喰い付こうと思ったのですが、価格を見てびっくり。
みたいな追記をしようと思ったのですが、長くなりそうだったので別記事にしました。
た、高ぇ~......
このページの内容を確認する意味もあって買おうと思ってたけど、ちょっと気軽には無理だわ......