美文网首页
iOS开发之3D Touch(快速添加3D Touch功能)

iOS开发之3D Touch(快速添加3D Touch功能)

作者: iOS发呆君 | 来源:发表于2020-12-11 13:49 被阅读0次

    1. 概述

    作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:196800191,加群密码:112233,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!

    在支持3D Touch的设备上,用户可以通过对触摸屏施加不同程度的压力来访问其他功能,应用程序可以通过显示上下文菜单(或支持Peek和Pop)来响应,以显示一些可供用户操作的选项或者行为。

    在运行iOS 13及以后版本的设备上,人们可以使用touch和hold手势来打开上下文菜单,而不管设备是否支持3D touch。在3D触摸设备上,手势可以更快地显示上下文菜单,对特性的独立访问。

    3D Touch主要分为两种:

    • 主屏幕快捷操作(Home Screen Quick Actions)
    • 预览和跳转(Peek and Pop)

    本文所有示例及代码全部基于xcode12,iOS13.

    2. 主屏幕快捷操作(Home Screen Quick Actions)

    当用户长按APP图标或者施加一定压力的时候,程序会在适当的位置展示出一个菜单选项列表。当用户选择一个快速动作时,APP启动,程序的应用委托对象接收到快速动作消息。

    配置一个主屏幕快捷操作,可分为静态和动态两种方式。

    2.1 静态添加快捷操作(Static quick actions)

    这种方式主要是在项目的Info.plist文件中添加相关的属性。

    参考如下:

    或者像下面这样配置,效果都一样:

        <array>
            <dict>
                <key>UIApplicationShortcutItemIconFile</key>
                <string>open-favorites</string>
                <key>UIApplicationShortcutItemTitle</key>
                <string>Favorites</string>
                <key>UIApplicationShortcutItemType</key>
                <string>com.mycompany.myapp.openfavorites</string>
                <key>UIApplicationShortcutItemUserInfo</key>
                <dict>
                    <key>key1</key>
                    <string>value1</string>
                </dict>
            </dict>
            <dict>
                <key>UIApplicationShortcutItemIconType</key>
                <string>UIApplicationShortcutIconTypeCompose</string>
                <key>UIApplicationShortcutItemTitle</key>
                <string>New Message</string>
                <key>UIApplicationShortcutItemType</key>
                <string>com.mycompany.myapp.newmessage</string>
                <key>UIApplicationShortcutItemUserInfo</key>
                <dict>
                    <key>key2</key>
                    <string>value2</string>
                </dict>
            </dict>
        </array>
    

    下面针对上面配置的key值来了解一下:

    Key 配置要求 描述
    UIApplicationShortcutItemType 必填 快捷操作项的唯一标识,用于区别其他快捷操作项。
    UIApplicationShortcutItemTitle 必填 快捷操作项的主标题.如果主标题能够一行显示的话,就一行显示。如果太长了一行显示不小的话,如果没有配置副标题,那么主标题显示两行。
    UIApplicationShortcutItemSubtitle 选填 快捷操作项的副标题,显示在主标题的下面。如果制定了副标题,但是主标题又太长了,那么主标题只显示一行,多余的打点。
    UIApplicationShortcutItemIconType 选填 配置系统提供的快捷操作项的图标。
    UIApplicationShortcutItemIconFile 选填 配置自定义的快捷操作项的图标,如果配置了这个key,那么系统将会忽略UIApplicationShortcutItemIconType自定义图标必须是方形的,单一颜色,尺寸为35x35 points。
    UIApplicationShortcutItemUserInfo 选填 快捷操作项的附加信息,字典类型。

    注明:这些key用在iOS9及以上且支持3D Touch的设备上。

    2.2 动态添加快捷操作(Dynamic quick actions)

    这种方式主要通过代码的形式把UIApplicationShortcutItem对象数组传递给UIApplication单例对象。

    UIApplicationShortcutItem就是屏幕上弹出的列表中列表项对应的数据模型,下面看一下这个类的初始化方法以及相关属性:

    方法或属性 描述
    init(type: String, localizedTitle: String) 初始化方法
    init(type: String, localizedTitle: String, localizedSubtitle: String?, icon: UIApplicationShortcutIcon?, userInfo: [String : NSSecureCoding]?) 初始化方法
    var localizedTitle: String 主标题
    var localizedSubtitle: String? 副标题
    var type: String 唯一标识
    var icon: UIApplicationShortcutIcon? 图标
    var userInfo: [String : NSSecureCoding]? 附加信息

    如果同时使用静态和动态的方法添加,其添加的先后顺序是:先添加静态UIApplicationShortcutItem对象,如果静态UIApplicationShortcutItem对象不足4个,则继续添加动态UIApplicationShortcutItem对象。官方文档提及到最多只能添加4个UIApplicationShortcutItem对象。

    下面看一下示例代码:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
            
            let dynamicIcon1 = UIApplicationShortcutIcon(systemImageName: "play")
            let dynamicItem1 = UIApplicationShortcutItem(type: "play", localizedTitle: "播放", localizedSubtitle: "播放喜欢的内容", icon: dynamicIcon1, userInfo: nil)
            
            let dynamicIcon2 = UIApplicationShortcutIcon(systemImageName: "message")
            let dynamicItem2 = UIApplicationShortcutItem(type: "message", localizedTitle: "消息", localizedSubtitle: "发送消息", icon: dynamicIcon2, userInfo: nil)
            
            let dynamicIcon3 = UIApplicationShortcutIcon(systemImageName: "favorite")
            let dynamicItem3 = UIApplicationShortcutItem(type: "favorite", localizedTitle: "喜欢", localizedSubtitle: "喜欢的节目", icon: dynamicIcon3, userInfo: nil)
            UIApplication.shared.shortcutItems = [dynamicItem1, dynamicItem2, dynamicItem3]
            
            return true
        }
    
    上面代码动态添加了3个UIApplicationShortcutItem对象,另外还配置了两个静态UIApplicationShortcutItem对象,如下图:
    最终运行结果如下,动态创建的第三个UIApplicationShortcutItem对象,没有显示出来。

    2.3 响应方法

    当点击对应的快捷操作项后,APP被唤醒或者启动.

    1. 当APP没有运行起来的时候,点击后APP启动,并且通过scene(_:willConnectTo:options:) 方法中的connectionOptions参数携带shortcut对象信息。这个方法中先保存shortcut对象信息,带APP完全启动后,再根据shortcut对象信息执行后续操作。

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        /** Process the quick action if the user selected one to launch the app.
            Grab a reference to the shortcutItem to use in the scene.
        */
        if let shortcutItem = connectionOptions.shortcutItem {
            // Save it off for later when we become active.
            savedShortCutItem = shortcutItem
        }
    }
    

    2. 当APP已经运行起来(包括压在后台),点击后APP唤醒,并且调用 [windowScene(_:performActionFor:completionHandler:)](https://developer.apple.com/documentation/uikit/uiwindowscenedelegate/3238088-windowscene)方法传递shortcut对象信息。

    func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
            print(shortcutItem.localizedTitle)
    }
    

    3. 预览和跳转(Peek and Pop)

    Peek和Pop是应用内的一种全新交互模式,当用户不断增加力量在控件上按压,会依次进入四个阶段:

    1. 轻按控件,除触发Peek的控件外,其他区域全部虚化 。
    2. 继续用力Peek被触发,展示Pop界面快照 。
    3. 向上滑动展示快捷选项 。
    4. 继续用力跳转进入Pop界面。

    比如iPhone手机的信息APP以及微信,都有这个功能。

    下面看一个Demo,Demo中会从一个tableview界面,按压cell调入到detail界面,其经过如下图:


    简书88.png


    上面四个图正好对应了四个阶段。

    如要想cell用力按压后有预览效果,首先需要向cell注册3D功能,代码如下:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
            cell?.textLabel?.text = "这是第\(indexPath.row)行"
            // 判断是否支持3D Touch功能。
            if traitCollection.forceTouchCapability == .available {
                self.registerForPreviewing(with: self, sourceView: cell!)
            }
            return cell!
    }
    

    注册完之后,需要实现其协议方法:

    @available(iOS 9.0, *)
    public protocol UIViewControllerPreviewingDelegate : NSObjectProtocol {
     
        // 该方法返回一个可供预览的视图,如果返回nil,则无预览图。
        @available(iOS, introduced: 9.0, deprecated: 13.0, renamed: "UIContextMenuInteraction")
        func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?
     
        // 实现该方法,则会跳入到预览图控制器界面。
        @available(iOS, introduced: 9.0, deprecated: 13.0, renamed: "UIContextMenuInteraction")
        func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController)
    }
    

    Demo中两个协议方法现实如下:

        func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
            // 获取按压的cell
            guard let cell = previewingContext.sourceView as? UITableViewCell else {
                return nil
            }
            // 获取cell的indexPath
            guard let indexPath = tableView.indexPath(for: cell) else {
                return nil
            }
            // sourceRect边界外部虚化。
            previewingContext.sourceRect = cell.frame
            let detailVC = DetailViewController(nibName: "DetailViewController", bundle: nil)
            detailVC.number = indexPath.row
            detailVC.title = "\(indexPath.row)"
            return detailVC
        }
        
        func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
            show(viewControllerToCommit, sender: self)
        }
    

    实现上述代码即可实现1、2、4个阶段的功能。

    如果要实现预览界面上滑显示快捷项列表,则需要在目标控制器复写previewActionItems属性。

    下面在目标控制器(DetailViewController)界面复写previewActionItems属性。

    override var previewActionItems: [UIPreviewActionItem] {
            let action1 = UIPreviewAction(title: "喜欢", style: .default) { (action, controller) in
                
            }
            let action2 = UIPreviewAction(title: "收藏", style: .default) { (action, controller) in
                
            }
            let action3 = UIPreviewAction(title: "删除", style: .default) { (action, controller) in
                
            }
            return [action1, action2, action3]
    }
    

    以上就完成了3D Touch功能,当然此功能不限于UITableView。在iOS13之后,上面的相关方法以及协议将会废弃,由UIContextMenuInteraction取代,关于UIContextMenuInteraction,在后续博文中将继续介绍,敬请关注!

    参考文档:

    https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/index.html#//apple_ref/doc/uid/TP40016543-CH1-SW1

    本篇文章出自https://blog.csdn.net/guoyongming925的博客,如需转载,请标明出处。
    原文作者:Daniel_Coder
    原文地址:https://www.jianshu.com/writer#/notebooks/48715467/notes/81067285/preview

    相关文章

      网友评论

          本文标题:iOS开发之3D Touch(快速添加3D Touch功能)

          本文链接:https://www.haomeiwen.com/subject/ytjjgktx.html