探究3D touch
简介
iOS 9+ / iPhone 6s +
- 提供访问app特性的便捷方式;
- 沉浸式的交互方式
- 提供连续性的用户体验(Peek and Pop)
主屏幕 Quick Actions
2 types:
Static
在Info.plist中定义
Dynamic
在app加载后通过代码动态创建;可以包含一个系统图标/自定义图标/通讯录地址123456789101112131415161718192021222324252627// 1. create a ShortcutIconlet contactName = "Lexi Torres"var cocntactIcon: UIApplicationShortcutIcon? = nilif CNContactStore.authorizationStatus(for: .contacts) == .authorized {let predicate = CNContact.predicateForContacts(matchingName: contactName)let contacts = try? CNContactStore().unifiedContacts(matching: predicate, keysToFetch: [])if let contact = contacts?.first {contactIcon = UIApplicationShortcutIcon(contact: contact)}}let icon = contactIcon ?? UIApplicationShortcutIcon(type: .message)// 2. create action using the iconlet type = "com.company.app.sendChatTo"let subtitle = "Send a chat"let shortcutItem1 = UIApplicationShortcutItem(type: type,localizedTitle: contactName ,localizedSubtitle: subtitle,icon: icon)// 3. add more shortcutItem if necessary...let shortcutItems = [shortcutItem1, ...]// 4. register to applicationapplication.shortcutItems = shortcutItems处理action
12345678910111213141516171819202122// on app activationfunc application(application: UIApplication,performActionFor shortcutItem: UIApplicationShortcutItem,completionHandler: @escaping(Bool) -> Void ){let didHandle: Bool = /* handle logic using shortcutItem */completionHandler(didHandle)}// on app launch, 在App完全退出的情况下,上面方法Handler返回的是NO。// 这就需要我们在下面方法中也加入相应的回调处理func application(application: UIApplication,didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {var performAdditionalHandling = trueif let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {/* handle logic using shortcutItem */performAdditionalHandling = false}return performAdditionalHandling}
最佳实践:
- 每个app都需要提供quick actions
- 用于high-value的任务上
- 使quick actions 可预测
- quick actions的处理逻辑要注意向前兼容(Be prepared to handle dynamic quick actions from a previous version of your app)
- 添加的功能不能只通过quick action才能使用
Peek and Pop
Registered View Controller
需要实现UIViewControllerPreviewingDelegate
123456789101112131415161718192021222324252627282930313233343536373839404142434445// 1. Comforming previewing delegateclass ChatTableViewControlelr: UITableViewController, UIViewControllerPreviewingDelegate {// 2. registeroverride func viewDidLoad() {super.viewDidLoad()...registerForPreviewing(with: self, sourceView: tableView)}// 3. previewing delegate implementfunc previewingContext(_ previewingContext: UIViewControllerPreviewing,viewControllerForLocation location: CGPoint) -> UIViewController? {guard let indexPath = tableView.indexPathForRow(at: location) else { return nil }let chatDetailViewController = ...chatDetailViewController.chatItem = chatItem(at: indexPath)let cellRect = tableView.rectForRow(at: indexPath)let sourceRect = previewingContext.sourceView.convert(cellRect, from: tableView)previewingContext.sourceRect = sourceRectreturn chatDetailViewController}func previewingContext(_ previewingContext: UIViewControllerPreviewing,commit viewControllerToCommit: UIViewController) {show(viewControllerToCommit, sender: self)}// optional actionsoverride func previewActionItems() -> [UIPreviewActionItem] {let heart = UIPreviewAction(title: "heart", style: .default) { (action, viewController) in// Send a heart}}// 也可以用UIPreviewActionGroup() 包装一组actionslet replyActions = [action1, action2]let sendReply = UIPreviewActionGroup(title: "a group reply" style: .default, actions: replyActions)return [heart, sendReply]}
其他的action styles: .selected, .destructive
- 最佳实践
- 能够被tapped的content应该支持 Peek and Pop
- Return a preview view controller consistently
- Don’t take too long in the previewing delegate
- Set the previewing context sourceRect
UIPreviewInteraction
同样的Peek and Pop处理过程 + 自动Haptic Feedback + 自定义界面
实现 UIPreviewInteractionDelegate
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950// 1. comfromextension ChatDetailViewController: UIPreviewInteractionDelegate {var replyPreviewInteraction: UIPreviewInteraction!}// 2. createoverride func viewDidLoad() {super.viewDidLoad()...replyPreviewInteraction = UIPreviewInteraction(view: view)replyPreviewInteraction.delegate = self}previewInteractionShouldBegin()// 3. preveiw transitionfunc previewInteraction(_ previewInteraction: UIPreviewInteraction,didUPdatePreveiwTransition transitionProgress: CGFloat,ended: Bool) {// progress value [0, 1]updateForPreview(progress: transitionProgress)if ended {completePreview()}}// 4. cancel handlingfunc previewInteractionDidCancel(_ previewInteraction: UIPreviewInteraction) {UIView.animate(withDuration: 0.4) {self.updateForPreview(progress: 0)self.resetToInitialAppearance()}}// 5. commit transitionfunc previewInteraction(_ previewInteraction: UIPreviewInteraction,didUpdateCommitTransition transitionProgress: CGFloat,ended: Bool) {updateForCommit(progress: transitionProgress)if ended {completeCommit()}}
Low-Level Force API
Properties on UITouch: force and maximumPossibleForce