[廃止予定]ユーザー体験を向上させるために、今すぐあなたのiOSアプリに3D TOUCH機能を追加しましょう(Swift)
iOS 3D TOUCH の活用
[廃止] 2020/06/14
iPhone 11以降のモデルでは3D Touch機能が廃止され、Haptic Touchに置き換えられています。実装方法も異なります。
先日、プロジェクト開発の合間に多くのiOSの面白い機能を探りました: CoreML 、 Vision 、 Notification Service Extension 、Notification Content Extension、Today Extension、Core Spotlight、Share Extension、SiriKit(一部は記事にまとめ済み、その他はお楽しみに🤣)
その中でも本日の主役は:3D Touch機能
この機能は iOS 9/iPhone 7以降 でサポートされており、私自身がiPhone 6からiPhone 8に変えて初めてその便利さを実感しました!
3D TouchはAPPで以下の2つの機能を実装できます:

- Preview ViewController プレビュー機能 — 結婚吧APP

- 3D Touch ショートカットアプリ起動機能
その中で、第一の機能は最も広く使われ、効果も高いものです(Facebook:ニュースフィードの内容プレビュー、Line:メッセージのチラ見)。第二のAPPショートカット起動は、現在のデータを見ると利用者が少ないため、最後に説明します。
1. Preview ViewController プレビュー機能:
機能のデモは上の図1に示されているように、ViewControllerのプレビュー機能をサポートしています。
-
3D Touchの強押し時の背景のぼかし
-
3D Touchで強く押したときにViewControllerのプレビューウィンドウを表示する
-
3D Touchで強く押すとViewControllerのプレビューウィンドウが表示され、上にスワイプすると下部にオプションメニューを追加できる
-
3D Touchの強押しを離してウィンドウに戻る
-
3D Touchで強く押してからさらに力を入れて目的のViewControllerに遷移する
ここでは、A:リスト画面 と B:ターゲット画面 に分けて実装するコードをそれぞれ示します:
B内では現在がプレビューか実際に画面に入っているかを判別する方法がないため、判定用の値を渡すProtocolを先に作成します。
protocol UIViewControllerPreviewable {
var is3DTouchPreview:Bool {get set} // 3D Touchプレビューかどうか
}
これで B 内で以下の判定ができるようになります:
class BViewController:UIViewController, UIViewControllerPreviewable {
var is3DTouchPreview:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
if is3DTouchPreview {
// プレビュー画面の場合…例えば:全画面表示にする、ツールバーを隠す
} else {
// 通常モードでは通常通り表示
}
}
A: リストビューは UITableView または UICollectionView で構成できます:
class AViewController:UIViewController {
//3D Touchが使えるViewを登録
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.forceTouchCapability == .available {
//TableView:
registerForPreviewing(with: self, sourceView: self.TableView)
//CollectionView:
registerForPreviewing(with: self, sourceView: self.CollectionView)
}
}
}
extension AViewController: UIViewControllerPreviewingDelegate {
//3D Touchを離した後の処理
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
//これから直接遷移するページなので、ViewControllerのプレビューモードを解除:
if var viewControllerToCommit = viewControllerToCommit as? UIViewControllerPreviewable {
viewControllerToCommit.is3DTouchPreview = false
}
self.navigationController?.pushViewController(viewControllerToCommit, animated: true)
}
//3D TouchのCell位置と表示したいViewControllerを制御
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
//現在のタップ位置のindexPathとcellの取得
//TableView:
guard let indexPath = TableView.indexPathForRow(at: location),let cell = TableView.cellForRow(at: indexPath) else { return nil }
//CollectionView:
guard let indexPath = CollectionView.indexPathForItem(at: location),let cell = CollectionView.cellForItem(at: indexPath) else { return nil }
//表示したいViewController
let targetViewController = UIStoryboard(name: "StoryboardName", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerIdentifier")
//背景をぼかす際の保持領域(通常はタップ位置)、図1参照
previewingContext.sourceRect = cell.frame
//3D Touchウィンドウのサイズ、デフォルトは自動調整で変更不要
//変更する場合は:targetViewController.preferredContentSize = CGSize(width: 0.0, height: 0.0)
//プレビューのViewControllerに現在プレビューモードであることを通知:
if var targetViewController = targetViewController as? UIViewControllerPreviewable {
targetViewController.is3DTouchPreview = true
}
//nilを返すと何の効果もなし
return nil
}
}
ご注意ください!3D Touchを登録するViewは“viewDidLoad”ではなく、traitCollectionDidChange内に配置する必要があります(こちらの記事を参照してください)
どこに追加すべきかについて、多くの失敗を経験しました。ネット上ではviewDidLoadに書く場合もあれば、cellForItem内に書く場合もありますが、どちらも時々動作しなかったり、一部のセルだけが動作しない問題が発生します。

付図1 背景ぼかし保持領域のイメージ図
もしスワイプアップ後に下部にオプションメニューを追加したい場合は、B の中に追加してください。BはB、BはBですよ!

override var previewActionItems: [UIPreviewActionItem] {
let profileAction = UIPreviewAction(title: "店舗情報を見る", style: .default) { (action, viewController) -> Void in
// タップ後の操作
}
return [profileAction]
}
空の配列を返すことでこの機能を使用しないことを示します。
完了!
2. APP ショートカット起動
ステップ1
info.plist に UIApplicationShortcutItems パラメータを追加し、タイプは Array に設定する
そして、その中にメニュー項目(Dictionary)を追加し、キーと値の設定は以下の通りです:
-
[必須] UIApplicationShortcutItemType : 識別文字列で、AppDelegateで判定に使用します
-
[必須] UIApplicationShortcutItemTitle : オプションのタイトル
-
UIApplicationShortcutItemSubtitle : オプションのサブタイトル

- UIApplicationShortcutItemIconType : システムアイコンを使用する

参考元はこちらの記事です。
-
UIApplicationShortcutItemIconFile : カスタムアイコンを使用(サイズ:35x35、単色)、UIApplicationShortcutItemIconTypeとどちらか一方を使用します
-
UIApplicationShortcutItemUserInfo : 追加情報の詳細例 EX: [id:1]

私の設定は上の図の通りです
第二ステップ
AppDelegateに処理用の関数を追加する
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
var info = shortcutItem.userInfo
switch shortcutItem.type {
case "searchShop":
//
case "topicList":
//
case "likeWorksPic":
//
case "marrybarList":
//
default:
break
}
completionHandler(true)
}
完了!
結語
APPに3D Touch機能を追加するのは難しくなく、ユーザーにとっても親切に感じられます❤;デザイン操作と組み合わせてユーザー体験を向上させることができます;しかし現在は上記の2つの機能しかなく、さらにiPhone 6s以下やiPad、iPhone XRは3D Touch非対応のため、実際に使える機能はさらに限られています。あくまで補助的に体験を増やす目的となります。
p.s.

もし細かくテストすると、上記の効果で、CollectionViewをスクロールしているときに一部の画像が画面外に滑り出している状態で押し込むと、上記のような状況が発生することに気づくでしょう😅
Post が Medium から ZMediumToMarkdown によって変換されました。



コメント