3D Touch 概要

# 3D Touch 概要

iOS 9 の隠し球 3D Touch がヤバそうなので、<del>現状の公開されている情報をもとに予習をしておきたいと思います。</del> 実機での操作感などを含めて概要をまとめたいと思います。

## 感圧 (Pressure Sensitivity)

iPhone 6s/6s Plus の圧力検知機能を利用して、たとえばペンやブラシの太さ、スタイルの変化を実装することができます。絵を描く創作系アプリなどに活用できます。

![](https://developer.apple.com/ios/3d-touch/images/pressure-sensitivity.jpg)

## チラ見とポップ (Peek and Pop)

OS X でいう QuickLook に操作性を追加したようなものでしょうか。
ユーザーは実際にコンテンツを開ききることなく、その中身をチラ見 (Peek) することができます。（いったん力を弱めて）そこからさらに押し込むとコンテンツをポップすることができます。圧力は大きく三段階に区別されますが、二段階目（チラ見）から三段階目（ポップ）にかけてはタッチが継続してさえいれば圧力を少し弱めてもチラ見状態が継続します。操作しにくい場合は二段階目（チラ見）で一呼吸おいてから押し直すと良いかもしれません。

※Peek を理解しやすいように、勝手に「チラ見」と訳しています。


### 三段階の圧力変化がどう作用するか

1. チラ見可能かの示唆（ぼかし状態）
2. チラ見状態（浮いている状態）
3. ポップして完全遷移

#### チラ見可能かの示唆

例えばセルを軽く押し込むと（他の要素がぼかされて）チラ見できることを示唆します。
このとき、指は画面から離さずタッチが継続しています。ここからさらに強く押し込むと「チラ見」ビューを表示します。

![](https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/Art/preview_available_2_2x.png)

#### チラ見 (Peek)

チラ見はビューが「浮いている状態」です。このとき、指は画面から離さずタッチイベントが継続しています。ここで指を離してタッチイベントを終了するとチラ見をやめて元の状態に戻ります。
ユーザーはここからさらに深く押し込むことでポップさせることができます。

![](https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/Art/peek_2x.png)


#### チラ見状態からのクイックアクション

例えばメールアプリではチラ見状態から上下左右にスワイプすることでクイックアクションを実施できます。メールを破棄したりアーカイブしたり返信したりといったことが瞬時に行えます。

![](https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/MobileHIG/Art/webview_peek_2x.png)

![](https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/MobileHIG/Art/webview_peek_quick_actions_2x.png)

## クイックアクション (Quick Actions)

ユーザーがもっとも頻繁に利用するアクションをより簡単に実行できるようになるショートカットメニューがホーム画面のアプリアイコンに追加されます。

ユーザーがアプリのアイコンを（タップではなく）軽く押し込むと振動と同時にアイコンの周りにベゼルが現れ、そこからショートカットメニューが表示されます。クイックアクションを選択するとアプリが起動して、UIApplicationDelegate に対してメッセージが通知されます。
クイックアクションに非対応のアプリを押し込むと表示上は何も起こりませんが、Taptic Engine の振動フィードバックでそれが非対応ということが理解できます。

![](https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/Art/maps_directions_home_2x.png)

## 静的アクションと動的アクション

アプリのクイックアクションには、静的アクション、動的アクションの二種類があります。

静的アクションはあらかじめ Info.plist で定義された組み込みアクションです。
動的アクションはその状態にふさわしいように適宜セットするアクションです。

クイックアクションは最大2行まで表示でき、独自のアイコンを設定することができます。


## App Switcher の新しい使い方

ホームボタンのダブルクリックで表示できる App Switcher 画面が 3D Touch ではより素早く行うことができます。画面の左隅あたりを少し強めに押し込むと（若干コツがいります）スワイプ状態になり、そこから前のアプリに直接切り替えたり App Switcher 画面に移ることができます。


## 3D Touch の感度を変更する、無効にする

アクセシビリティ設定画面から感度を変更したり無効にすることができます。これは開発の際のテストにも活用できます。


## 実装にあたって

Xcode 7.0 が必須ですが、シミュレータではサポートされません……とガイドには書いてあったのですが、「Force Touch Pressure」という項目が存在します。ただ、私の環境では有効になりません。Interface Builder でもサポートされないのでコードで実装して iPhone 6s 実機を用いて確認する必要がありそうです。

3D Touch は Force Touch とも呼称されることがあります。以前は Force Touch の名でブランディングされていたのが直前に変更になったのでしょうか。
また Peek は Preview とも呼称されることがあります。

# Human Interface Guidelines

UI の設計の前にまずは Human Interface Guidelines を読みましょう。

https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/MobileHIG/3DTouch.html

## 3D Touch を実装するにあたっての諸注意

UX の観点から、次のことには注意しましょう。

**チラ見のみはダメ：**
チラ見を実装するなら必ずポップできるようにしましょう。

**チラ見ビューの見た目に注意：**
チラ見ビューにボタンに見える要素を配置すると間違って押そうとして指を離してしまう（チラ見状態から抜けてしまう）ことがあるため、ボタンなどは配置しないようにしましょう。

**アクションを実施するにあたって 3D Touch を唯一の手段とはしない：**
3D Touch はあくまでショートカットの一種と捉えましょう。ショートカット知らなくても、あるいはそれを実施できない環境であってもアクションにたどり着けるようにします。（iPhone 6以前の機種、古い OS、設定で無効化され得ることを考慮する。）

※PC のショートカットキーやコンテクストメニューと同じ考え方。

**ホーム画面クイックアクションを「近道」のために利用しない：**
画面遷移を省略するためだけにクイックアクションを利用しないこと。「近道」が必要ならそもそも画面設計に問題があると考えられます。

**ホーム画面クイックアクションを「通知」のために利用しない：**
通知を実装する手段は他にあります。アプリケーションバッジやローカル通知などを検討しましょう。

**ホーム画面クイックアクションは「予測できる範囲」で利用する：**
例えばマップアプリなら「『現在地検索』クイックアクション」といった、アプリからある程度予測できそうな機能を実装しましょう。


**ホーム画面クイックアクションはアプリの配置によってレイアウトが変化する：**
ホーム画面において、アプリが左寄りにある場合はアイコンも左側に、右寄りの場合は右側になります。（アラビア語などの右横書き言語環境では未確認。）
![qa.jpg](https://qiita-image-store.s3.amazonaws.com/0/3603/061d698a-ea47-f24c-8757-1858b22eeb4c.jpeg)


# 3D Touch API

[Adopting 3D Touch on iPhone](https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/3DTouchAPIs.html)

3D Touch API は主に次の四種類に大別されます。

- UITouch の感圧プロパティ
- ホーム画面向けのクイックアクション API
- UIKit に追加されたチラ見とポップ API
- Web View 向けのチラ見とポップ API

将来（iOS 9.1）はここに Apple Pencil 向けの筆圧・傾き検知なども加わると思われます。
そしてこれらを利用する前に必ずランタイムで API が利用可能かをチェックする必要があります。

## 3D Touch が利用可能かをチェックする

iOS 8 で追加された `UITraitCollection` クラスを利用しますが、今回利用する `forceTouchCapability` プロパティは当然 iOS 9 以降なので注意してください。このプロパティが返す enum 値 `UIForceTouchCapability` によって利用可能かを判断します。また、このクラスあるいはプロパティが実装されていない場合はそもそも 3D Touch が利用できない環境だと判断できます。

```objc:UITraitCollection
@property(nonatomic, readonly) UIForceTouchCapability forceTouchCapability
```
```objc:UIForceTouchCapability
typedef NS_ENUM (NSInteger, UIForceTouchCapability) {
   UIForceTouchCapabilityUnknown = 0,
   UIForceTouchCapabilityUnavailable = 1,
   UIForceTouchCapabilityAvailable = 2
};
```

## 感圧検知

`UITouch` クラスに二種類のプロパティが追加されます。

`force` はタッチの圧力です。1.0のときはタッチの「平均的」圧力を示します。`majorRadius` とは違って浮動小数点で連続的に細かく値を取得することができます。最大値は6.666667で、感度の設定がどう影響するのかはよくわかりませんでした。なお、設定で 3D Touch を無効にした場合はいずれも0.0を返します。

```objc:UITouch
@property(nonatomic, readonly) CGFloat force
```

`maximumPossibleForce` は `force` の最大値です。この値に達するときには十分に押下されています。

```objc:UITouch
@property(nonatomic, readonly) CGFloat maximumPossibleForce
```

## ホーム画面クイックアクション

静的アクションは Info.plist に UIApplicationShortcutItems アレイを定義します。
動的アクションは `UIApplicationShortcutItem` または `UIMutableApplicationShortcutItem` クラスで定義し、UIApplication オブジェクトにそれを登録します。

- [UIApplicationShortcutItems](https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/uid/TP40009252-SW36)
- [UIApplicationShortcutItem](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIApplicationShortcutItem_class/index.html)

クイックアクションからのイベントは UIApplicationDelegate に対して通知されます。
自身のクイックアクションが完了したら `completionHandler` に返却します。

```objc:UIApplicationDelegate
- (void)application:(UIApplication *)application
performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
  completionHandler:(void (^)(BOOL succeeded))completionHandler
```


## チラ見とポップ (UIKit)

UIViewController でチラ見とポップ、チラ見画面でのクイックアクションを利用することができます。

### 実装の手立て

UIViewControllerにプレビュー（チラ見）VCを登録：

```objc:UIViewController
- (id<UIViewControllerPreviewing>)registerForPreviewingWithDelegate(id<UIViewControllerPreviewingDelegate>)delegate
sourceView:(UIView *)sourceView
```

UIViewControllerからプレビュー（チラ見）VCを削除：

```objc:UIViewController
- (void)unregisterForPreviewingWithContext:(id<UIViewControllerPreviewing>)previewing
```

ソースビューが押下されたとき（ぼかされるとき）に UIViewControllerPreviewingDelegate に通知される：

```objc:UIViewControllerPreviewingDelegate
- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext
viewControllerForLocation:(CGPoint)location
```

UIPreviewAction はチラ見画面を上方向にスワイプした際に表示されるクイックアクションです。

- UIPreviewAction
- UIPreviewActionGroup
- UIPreviewActionItem

## チラ見とポップ (Web View)

WKWebView, UIWebView, SFSafariViewController でチラ見とポップを利用することができます。

WKWebView と UIWebView にはリンク先をチラ見できるようになる `allowsLinkPreview` プロパティがあります。SFSafariViewController ではこれが自動的に作用します。

## JavaScript での実装

こちらの記事が参考になります。
http://qiita.com/items/6e77ba0c778b8eaf8514