iOS 3D Touch开发(完整、详细版)

一、3D Touch 简介

在iOS 9中,新 iPhone 将第三维度添加到了用户界面。

  • 用户现在可以用力摁下主屏按钮来快速调出应用提供的功能菜单。
  • 在应用中,用户现在可以用力摁下视图以查看更多内容的预览并且快速访问一些功能。
Home Screen Quick Actions

本文主要讲解 3D Touch 各种场景下的开发方法,开发主屏幕应用 icon 上的快捷选项标签(Home Screen Quick Actions),静态设置 UIApplicationShortcutItem ,动态添加 UIApplicationShortcutItem,以及 Peek 和 Pop 的实现。

二、Home Screen Quick Actions

添加Home Screen Quick Actions有两种方式:
1、通过Plist文件静态设置;
2、通过代码动态添加。

两种方法的区别在于:通过Plist设置无需运行程序,也就是说在下载App后,不需要打开应用,就可以即可唤出Home Screen Quick Actions;而通过代码动态添加的,必须在第一次下载后打开App,才能出现Home Screen Quick Actions。

1. 通过Plist文件静态设置

在应用的 Info.plist 文件中添加UIApplicationShortcutItems数组。
数组中添加字典,如下图所示:

Info.plist文件配置

其中,字典的Key有以下选项:

名称 说明 是否必须
UIApplicationShortcutItemTitle 标签的标题 必填
UIApplicationShortcutItemType 标签的唯一标识 必填
UIApplicationShortcutItemIconType 使用系统图标的类型,如搜索、定位、home等 可选
UIApplicationShortcutItemIconFile 使用项目中的图片作为标签图标 可选
UIApplicationShortcutItemSubtitle 标签副标题 可选
UIApplicationShortcutItemUserInfo 字典信息,如传值使用 可选

第一个图片使用系统自带的,第二个是使用Assets.xcassets文件夹中的图片,当完成设置后,效果如下:

通过Plist文件静态设置
2. 通过代码动态添加
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
     let item1 = UIApplicationShortcutItem(type: "2", localizedTitle: "code add item1", localizedSubtitle: "code add subtitle", icon: UIApplicationShortcutIcon(templateImageName: "shortcut_scorecard"), userInfo: nil)
     let item2 = UIApplicationShortcutItem(type: "3", localizedTitle: "code add item2", localizedSubtitle: nil, icon: UIApplicationShortcutIcon(type: .add), userInfo: nil)
        
     application.shortcutItems = [item1, item2]
     return true
}

效果如下:

通过代码动态添加

注意:目前Home Screen Quick Actions最多只能添加4个。
无论用哪种方式添加,当点击item后,都会调用AppDelegate中的application(_:performActionFor:completionHandler:)方法:

func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
     print(shortcutItem.type) // 通过type来判断是点击了哪一个按钮
}

三、Peek and Pop(预览与跳转)

  • Peek:轻按,屏幕视图就会过渡到Peek,一个你设置的用来展示更多内容的视图-就像Mail app做的一样。如果用户这时结束了触碰,Peek就会消失并且应用回到交互开始之前的状态。当你用力按下屏幕按到一定程度时,系统会弹出一个预览视图,这个过程就称之为Peek。
  • Pop:或者这个时候,用户可以在peek界面上更用力按下来跳转到使用peek呈现的视图,这个过渡动画会使用系统提供的pop过渡。pop出来的视图会填满你应用的根视图并显示一个返航按钮可以回到交互开始的地方。再用力按下去就会展开到预览视图的控制器,这过程就是Pop。

实现步骤:

  1. 注册预览代理
// Registers a view controller to participate with 3D Touch preview (peek) and commit (pop).
@available(iOS 9.0, *)
// 第一个参数:代理
// 第二个参数:哪个view执行Peek
open func registerForPreviewing(with delegate: UIViewControllerPreviewingDelegate, sourceView: UIView) -> UIViewControllerPreviewing
  1. 遵守协议:UIViewControllerPreviewingDelegate
  2. 实现协议方法
// If you return nil, a preview presentation will not be performed
@available(iOS 9.0, *)
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?
@available(iOS 9.0, *)
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController)

接下来用一个tableView的例子🌰来说明,实现以下效果:



代码如下:

import UIKit

class ViewController: UIViewController {
    
    fileprivate lazy var array = [String]()
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        for i in 0...20 { array.append("第\(i)行") }
        // 注册Cell
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        // 判断系统版本,必须iOS 9及以上,同时检测是否支持触摸力度识别
        if #available(iOS 9.0, *), traitCollection.forceTouchCapability == .available {
            // 注册预览代理,self监听,tableview执行Peek
            registerForPreviewing(with: self, sourceView: tableView)
        }
    }
}

// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return array.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
        cell.textLabel?.text = array[indexPath.row]
        return cell
    }
}

// MARK: - UIViewControllerPreviewingDelegate
@available(iOS 9.0, *)
extension ViewController: UIViewControllerPreviewingDelegate {
    
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        // 模态弹出需要展现的控制器
        showDetailViewController(viewControllerToCommit, sender: nil)
        // 通过导航栏push需要展现的控制器
        // show(viewControllerToCommit, sender: nil)
    }
    
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        // 获取indexPath和cell
        guard let indexPath = tableView.indexPathForRow(at: location), let cell = tableView.cellForRow(at: indexPath) else { return nil }
        // 设置Peek视图突出显示的frame
        previewingContext.sourceRect = cell.frame
        let vc = DetalViewController()
        // 返回需要弹出的控制权
        return vc
    }
}

在实际开发中,你可能会用到 UIView中的坐标转换 的几个方法(可跳过不看):

// 将像素point由point所在视图转换到目标视图view中,返回在目标视图view中的像素值
open func convert(_ point: CGPoint, to view: UIView?) -> CGPoint
// 例如:point2 = view1.convert(point1, toView: view2):把point1从view1的坐标系中,转换到view2的坐标系中

// 将像素point从view中转换到当前视图中,返回在当前视图中的像素值
open func convert(_ point: CGPoint, from view: UIView?) -> CGPoint
// 例如:point2 = view1.convert(point1, from: view2):把point1从view2的坐标系中,转换到view1的坐标系中

// 将rect由rect所在视图转换到目标视图view中,返回在目标视图view中的rect
open func convert(_ rect: CGRect, to view: UIView?) -> CGRect
// 例如:rect2 = view1.convert(rect1, toView: view2):把rect1从view1的坐标系中,转换到view2的坐标系中

// 将rect从view中转换到当前视图中,返回在当前视图中的rect
open func convert(_ rect: CGRect, from view: UIView?) -> CGRect
// 例如:rect2 = view1.convert(rect1, toView: view2):把rect1从view2的坐标系中,转换到view1的坐标系中

四、Peek快速选项

如果用户一直保持触摸,可以向上滑动Peek视图,系统会展示出你预先设置和peek关联的peek快速选项。
每一项peek快速选项都是你应用中的深度链接。当peek快速选项出现后,用户可以停止触摸而且peek会停留在屏幕中。用户可点击一个快速选项,唤出相关链接。


在本例中,实现以上效果,只需要在DetalViewController中添加以下代码即可:

import UIKit

class DetalViewController: UIViewController {
    
    @available(iOS 9.0, *)
    lazy var previewActions: [UIPreviewActionItem] = {
        let a = UIPreviewAction(title: "这是一个default按钮", style: .default, handler: { (action, vc) in
            // 这里实现点击按钮事件处理
        })
        let b = UIPreviewAction(title: "这是一个destructive按钮", style: .destructive, handler: { (action, vc) in
            // 这里实现点击按钮事件处理
        })
        return [a, b]
    }()
    
    @available(iOS 9.0, *)
    override var previewActionItems: [UIPreviewActionItem] {
        return previewActions
    }
}

最后注意:以上全部功能必须要求为 iPhone 6s 及以上机型,并且是 iOS 9 及以上,才有效果,模拟器可以看到效果,不需要安装任何插件,但必须要有触摸盘才行,在触摸盘上的点击就是3D Touch。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 前言 关于这篇文章 由于iPhone 6S发布不到一年的时间,很多新特性、新技术还未普遍,不管是3D Touch的...
    Tangentw阅读 4,466评论 8 18
  • 3D Touch 给iOS9的用户一个维度的交互。在支持的设备上,人们能够在主屏幕界面通过按压应用程序图标,快速的...
    Jack__yang阅读 585评论 0 2
  • 前言 关于3D touch苹果官方文档是这么开始介绍的: 大意如下:iOS9开始,所有新的手机都增加了一个三维的用...
    VV木公子阅读 2,206评论 3 39
  • iOS 9设计规范 中文版 完整版译者注:本文译自苹果官方人机界面指南 iOS Human Interface G...
    海宁Hennie阅读 13,260评论 2 60
  • 专著:http://www.jianshu.com/p/3443a3b27b2d 1.简单的介绍一下3D Touc...
    violafa阅读 1,007评论 1 0