Swift 中的 3D Touch:实现 Peek 和 Pop

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

iPhone 6s 上我最喜欢的功能之一是新的 3D Touch Peek and Pop 。 Peek 和 Pop 依靠压力敏感度为用户提供按下(peek)弹出的瞬态预览,或者允许他们通过更深的按下(pop)来导航该项目。两者都提供令人满意的触觉点击和偷看也可以显示一组上下文敏感的预览操作。

碰巧在过去一周左右的时间里,我一直在更新基于 PHImageManager 照片浏览器 。这是我 在一月份开始的 一个项目,我想更新到 Swift 2 以包含在下一版本的 Nodality 中。尽管 Nodality 是一款 iPad 应用程序,但该组件是通用的,是我首次涉足 Peek and Pop 的完美候选者。

交互设计

对于非 3D Touch 设备,我的照片浏览器的交互设计非常简单,顶部分段控件允许用户在他们的收藏之间导航,触摸图像选择它并将控制权返回给主机应用程序。通过长按,用户可以通过 UIAlertController 切换项目的收藏状态。

对于 3D Touch 设备,用户可以单击图像以弹出速览预览,然后通过 UIPreviewAction 切换收藏夹状态。更深的弹出选择图像并将控制权返回给主机应用程序。

配置

我不想失去非 3D Touch 设备的长按功能,因此在初始化期间,我查看了 traitCollection o 注册照片浏览器以进行预览或实现长按手势识别器。因为组件本身是模态呈现的,它的 traitCollection 声称不启用强制触摸,所以我查看应用程序关键窗口的 raitCollection:


 if UIApplication.sharedApplication().keyWindow?.traitCollection.forceTouchCapability == UIForceTouchCapability.Available
    {
        registerForPreviewingWithDelegate(self, sourceView: view)
    }
    else
    {
        let longPress = UILongPressGestureRecognizer(target: self, action: "longPressHandler:")
        collectionViewWidget.addGestureRecognizer(longPress)
}

偷看

要注册照片浏览器以使用委托进行预览,它必须实现 UIViewControllerPreviewingDelegate 并且为了查看,调用 previewingContext(viewControllerForLocation)。在这里我只需要返回一个我想充当预览的视图控制器的实例。当用户触摸图像时,我实例化了一个名为 touchedCel 的元组,类型为 (UICollectionViewCell, NSIndexPath),它引用触摸的图像,通过它我可以获得预览所需的 PHAsset 并将其交给我的 PeekViewController:


 if UIApplication.sharedApplication().keyWindow?.traitCollection.forceTouchCapability == UIForceTouchCapability.Available
    {
        registerForPreviewingWithDelegate(self, sourceView: view)
    }
    else
    {
        let longPress = UILongPressGestureRecognizer(target: self, action: "longPressHandler:")
        collectionViewWidget.addGestureRecognizer(longPress)
}

预览视图控制器 PeekViewController 重用了 ImageItemRenderer - 与我的主 UICollectionView 相同的项目渲染器,因此请求缩略图大小的图像的所有代码都已经可用:


 if UIApplication.sharedApplication().keyWindow?.traitCollection.forceTouchCapability == UIForceTouchCapability.Available
    {
        registerForPreviewingWithDelegate(self, sourceView: view)
    }
    else
    {
        let longPress = UILongPressGestureRecognizer(target: self, action: "longPressHandler:")
        collectionViewWidget.addGestureRecognizer(longPress)
}

添加预览操作以切换资产的收藏夹状态,这很简单,只需返回一个 UIPreviewActionItem 数组即可。 PeekViewController 已经知道需要切换什么资产并且共享照片库是一个单例,所以代码只是:


 if UIApplication.sharedApplication().keyWindow?.traitCollection.forceTouchCapability == UIForceTouchCapability.Available
    {
        registerForPreviewingWithDelegate(self, sourceView: view)
    }
    else
    {
        let longPress = UILongPressGestureRecognizer(target: self, action: "longPressHandler:")
        collectionViewWidget.addGestureRecognizer(longPress)
}

最终的结果,代码很少,是一个功能齐全的“peek”,带有漂亮的系统动画和令人满意的触觉点击:

弹出

弹出更容易。在这里,我实现了 UIViewControllerPreviewingDelegate 的 previewingContext(commitViewController) 方法。我的照片浏览器有一个名为 requestImageForAsset() 的方法,它请求资产的图像,然后关闭浏览器,所以我只需调用它:


 if UIApplication.sharedApplication().keyWindow?.traitCollection.forceTouchCapability == UIForceTouchCapability.Available
    {
        registerForPreviewingWithDelegate(self, sourceView: view)
    }
    else
    {
        let longPress = UILongPressGestureRecognizer(target: self, action: "longPressHandler:")
        collectionViewWidget.addGestureRecognizer(longPress)
}

结论

我只用了几个小时的手机,就已经发现偷看和弹出手机是一种非常自然的互动方式。考虑到可以实现 peek 和 pop 的简单性,我谦虚地建议将它添加到您自己的应用程序中是一个非常大的胜利!

与往常一样,该项目的源代码可在 我的 GitHub 存储库 中获取。享受!