The ins and outs of Apple's new 3D Touch technology. If you're not familiar with 3D Touch, it's a new technology from Apple that allows their latest mobile devices to measure the pressure of each touch on the screen. This in turn makes it possible to introduce many new gestures and interactions, like Quick Actions and Peek and Pop. How do these things work and how you can use them in your applications? If you're interested in the answer to that question, you should definitely check out this presentation.
4. UITouch.force
public class UITouch : NSObject {
// …
// Force of the touch, where 1.0 represents the force of an average touch
public var force: CGFloat { get }
// Maximum possible force with this input mechanism
public var maximumPossibleForce: CGFloat { get }
// …
}
5. UITouch.force
public class UITouch : NSObject {
// …
// Force of the touch, where 1.0 represents the force of an average touch
public var force: CGFloat { get }
// Maximum possible force with this input mechanism
public var maximumPossibleForce: CGFloat { get }
// …
}
For some reason equal to 6.66…
on the iPhone 6s
6. UITouch.force
public class UITouch : NSObject {
// …
// Force of the touch, where 1.0 represents the force of an average touch
public var force: CGFloat { get }
// Maximum possible force with this input mechanism
public var maximumPossibleForce: CGFloat { get }
// …
}
19. Dynamic Quick Actions
extension UIApplication {
// Register shortcuts to display on the home screen, or retrieve currently registered shortcuts.
@available(iOS 9.0, *)
public var shortcutItems: [UIApplicationShortcutItem]?
}
20. Dynamic Quick Actions
@available(iOS 9.0, *)
public class UIApplicationShortcutItem : NSObject, NSCopying, NSMutableCopying {
public init(type: String,
localizedTitle: String,
localizedSubtitle: String?,
icon: UIApplicationShortcutIcon?,
userInfo: [NSObject : AnyObject]?)
public convenience init(type: String,
localizedTitle: String)
// An application-specific string that identifies the type of action to perform.
public var type: String { get }
// Properties controlling how the item should be displayed on the home screen.
public var localizedTitle: String { get }
public var localizedSubtitle: String? { get }
@NSCopying public var icon: UIApplicationShortcutIcon? { get }
// Application-specific information needed to perform the action.
// Will throw an exception if the NSDictionary is not plist-encodable.
public var userInfo: [String : NSSecureCoding]? { get }
}
extension UIApplication {
// Register shortcuts to display on the home screen, or retrieve currently registered shortcuts.
@available(iOS 9.0, *)
public var shortcutItems: [UIApplicationShortcutItem]?
}
21. Dynamic Quick Actions
@available(iOS 9.0, *)
public class UIApplicationShortcutItem : NSObject, NSCopying, NSMutableCopying {
public init(type: String,
localizedTitle: String,
localizedSubtitle: String?,
icon: UIApplicationShortcutIcon?,
userInfo: [NSObject : AnyObject]?)
public convenience init(type: String,
localizedTitle: String)
// An application-specific string that identifies the type of action to perform.
public var type: String { get }
// Properties controlling how the item should be displayed on the home screen.
public var localizedTitle: String { get }
public var localizedSubtitle: String? { get }
@NSCopying public var icon: UIApplicationShortcutIcon? { get }
// Application-specific information needed to perform the action.
// Will throw an exception if the NSDictionary is not plist-encodable.
public var userInfo: [String : NSSecureCoding]? { get }
}
extension UIApplication {
// Register shortcuts to display on the home screen, or retrieve currently registered shortcuts.
@available(iOS 9.0, *)
public var shortcutItems: [UIApplicationShortcutItem]?
}
Required
Optional
22. Dynamic Quick Actions
let iconTypeIcon = UIApplicationShortcutIcon(type: .Search)
let iconTypeItem = UIApplicationShortcutItem(type: "icon-type-item",
localizedTitle: "Search",
localizedSubtitle: "icon from an icon type",
icon: iconTypeIcon,
userInfo: nil)
let templateIcon = UIApplicationShortcutIcon(templateImageName: "triangle")
let templateItem = UIApplicationShortcutItem(type: "template-item",
localizedTitle: "Triangle",
localizedSubtitle: "icon from template image",
icon: templateIcon,
userInfo: nil)
let contactStoreContactIcon = UIApplicationShortcutIcon(contact: contactFromContactStore)
let contactStoreContactItem = UIApplicationShortcutItem(type: "real-contact-item",
localizedTitle: "Karol",
localizedSubtitle: "icon from real contact",
icon: contactStoreContactIcon,
userInfo: nil)
let temporaryContact = CNMutableContact()
temporaryContact.givenName = "Hiro";
temporaryContact.familyName = "Protagonist";
// this will be ignored
temporaryContact.imageData = UIImagePNGRepresentation(UIImage(named: "triangle")!)
let temporaryContactIcon = UIApplicationShortcutIcon(contact: temporaryContact)
let temporaryContactItem = UIApplicationShortcutItem(type: "temporary-contact-item",
localizedTitle: "Hiro",
localizedSubtitle: "icon from tmp contact",
icon: temporaryContactIcon,
userInfo: nil)
UIApplication.sharedApplication().shortcutItems = [iconTypeItem, templateItem,
contactStoreContactItem, temporaryContactItem]
23. Dynamic Quick Actions
let iconTypeIcon = UIApplicationShortcutIcon(type: .Search)
let iconTypeItem = UIApplicationShortcutItem(type: "icon-type-item",
localizedTitle: "Search",
localizedSubtitle: "icon from an icon type",
icon: iconTypeIcon,
userInfo: nil)
let templateIcon = UIApplicationShortcutIcon(templateImageName: "triangle")
let templateItem = UIApplicationShortcutItem(type: "template-item",
localizedTitle: "Triangle",
localizedSubtitle: "icon from template image",
icon: templateIcon,
userInfo: nil)
let contactStoreContactIcon = UIApplicationShortcutIcon(contact: contactFromContactStore)
let contactStoreContactItem = UIApplicationShortcutItem(type: "real-contact-item",
localizedTitle: "Karol",
localizedSubtitle: "icon from real contact",
icon: contactStoreContactIcon,
userInfo: nil)
let temporaryContact = CNMutableContact()
temporaryContact.givenName = "Hiro";
temporaryContact.familyName = "Protagonist";
// this will be ignored
temporaryContact.imageData = UIImagePNGRepresentation(UIImage(named: "triangle")!)
let temporaryContactIcon = UIApplicationShortcutIcon(contact: temporaryContact)
let temporaryContactItem = UIApplicationShortcutItem(type: "temporary-contact-item",
localizedTitle: "Hiro",
localizedSubtitle: "icon from tmp contact",
icon: temporaryContactIcon,
userInfo: nil)
UIApplication.sharedApplication().shortcutItems = [iconTypeItem, templateItem,
contactStoreContactItem, temporaryContactItem]
24. Dynamic Quick Actions
let iconTypeIcon = UIApplicationShortcutIcon(type: .Search)
let iconTypeItem = UIApplicationShortcutItem(type: "icon-type-item",
localizedTitle: "Search",
localizedSubtitle: "icon from an icon type",
icon: iconTypeIcon,
userInfo: nil)
let templateIcon = UIApplicationShortcutIcon(templateImageName: "triangle")
let templateItem = UIApplicationShortcutItem(type: "template-item",
localizedTitle: "Triangle",
localizedSubtitle: "icon from template image",
icon: templateIcon,
userInfo: nil)
let contactStoreContactIcon = UIApplicationShortcutIcon(contact: contactFromContactStore)
let contactStoreContactItem = UIApplicationShortcutItem(type: "real-contact-item",
localizedTitle: "Karol",
localizedSubtitle: "icon from real contact",
icon: contactStoreContactIcon,
userInfo: nil)
let temporaryContact = CNMutableContact()
temporaryContact.givenName = "Hiro";
temporaryContact.familyName = "Protagonist";
// this will be ignored
temporaryContact.imageData = UIImagePNGRepresentation(UIImage(named: "triangle")!)
let temporaryContactIcon = UIApplicationShortcutIcon(contact: temporaryContact)
let temporaryContactItem = UIApplicationShortcutItem(type: "temporary-contact-item",
localizedTitle: "Hiro",
localizedSubtitle: "icon from tmp contact",
icon: temporaryContactIcon,
userInfo: nil)
UIApplication.sharedApplication().shortcutItems = [iconTypeItem, templateItem,
contactStoreContactItem, temporaryContactItem]
25. Dynamic Quick Actions
let iconTypeIcon = UIApplicationShortcutIcon(type: .Search)
let iconTypeItem = UIApplicationShortcutItem(type: "icon-type-item",
localizedTitle: "Search",
localizedSubtitle: "icon from an icon type",
icon: iconTypeIcon,
userInfo: nil)
let templateIcon = UIApplicationShortcutIcon(templateImageName: "triangle")
let templateItem = UIApplicationShortcutItem(type: "template-item",
localizedTitle: "Triangle",
localizedSubtitle: "icon from template image",
icon: templateIcon,
userInfo: nil)
let contactStoreContactIcon = UIApplicationShortcutIcon(contact: contactFromContactStore)
let contactStoreContactItem = UIApplicationShortcutItem(type: "real-contact-item",
localizedTitle: "Karol",
localizedSubtitle: "icon from real contact",
icon: contactStoreContactIcon,
userInfo: nil)
let temporaryContact = CNMutableContact()
temporaryContact.givenName = "Hiro";
temporaryContact.familyName = "Protagonist";
// this will be ignored
temporaryContact.imageData = UIImagePNGRepresentation(UIImage(named: "triangle")!)
let temporaryContactIcon = UIApplicationShortcutIcon(contact: temporaryContact)
let temporaryContactItem = UIApplicationShortcutItem(type: "temporary-contact-item",
localizedTitle: "Hiro",
localizedSubtitle: "icon from tmp contact",
icon: temporaryContactIcon,
userInfo: nil)
UIApplication.sharedApplication().shortcutItems = [iconTypeItem, templateItem,
contactStoreContactItem, temporaryContactItem]
26. Dynamic Quick Actions
let iconTypeIcon = UIApplicationShortcutIcon(type: .Search)
let iconTypeItem = UIApplicationShortcutItem(type: "icon-type-item",
localizedTitle: "Search",
localizedSubtitle: "icon from an icon type",
icon: iconTypeIcon,
userInfo: nil)
let templateIcon = UIApplicationShortcutIcon(templateImageName: "triangle")
let templateItem = UIApplicationShortcutItem(type: "template-item",
localizedTitle: "Triangle",
localizedSubtitle: "icon from template image",
icon: templateIcon,
userInfo: nil)
let contactStoreContactIcon = UIApplicationShortcutIcon(contact: contactFromContactStore)
let contactStoreContactItem = UIApplicationShortcutItem(type: "real-contact-item",
localizedTitle: "Karol",
localizedSubtitle: "icon from real contact",
icon: contactStoreContactIcon,
userInfo: nil)
let temporaryContact = CNMutableContact()
temporaryContact.givenName = "Hiro";
temporaryContact.familyName = "Protagonist";
// this will be ignored
temporaryContact.imageData = UIImagePNGRepresentation(UIImage(named: "triangle")!)
let temporaryContactIcon = UIApplicationShortcutIcon(contact: temporaryContact)
let temporaryContactItem = UIApplicationShortcutItem(type: "temporary-contact-item",
localizedTitle: "Hiro",
localizedSubtitle: "icon from tmp contact",
icon: temporaryContactIcon,
userInfo: nil)
UIApplication.sharedApplication().shortcutItems = [iconTypeItem, templateItem,
contactStoreContactItem, temporaryContactItem]
27. Dynamic Quick Actions
let iconTypeIcon = UIApplicationShortcutIcon(type: .Search)
let iconTypeItem = UIApplicationShortcutItem(type: "icon-type-item",
localizedTitle: "Search",
localizedSubtitle: "icon from an icon type",
icon: iconTypeIcon,
userInfo: nil)
let templateIcon = UIApplicationShortcutIcon(templateImageName: "triangle")
let templateItem = UIApplicationShortcutItem(type: "template-item",
localizedTitle: "Triangle",
localizedSubtitle: "icon from template image",
icon: templateIcon,
userInfo: nil)
let contactStoreContactIcon = UIApplicationShortcutIcon(contact: contactFromContactStore)
let contactStoreContactItem = UIApplicationShortcutItem(type: "real-contact-item",
localizedTitle: "Karol",
localizedSubtitle: "icon from real contact",
icon: contactStoreContactIcon,
userInfo: nil)
let temporaryContact = CNMutableContact()
temporaryContact.givenName = "Hiro";
temporaryContact.familyName = "Protagonist";
// this will be ignored
temporaryContact.imageData = UIImagePNGRepresentation(UIImage(named: "triangle")!)
let temporaryContactIcon = UIApplicationShortcutIcon(contact: temporaryContact)
let temporaryContactItem = UIApplicationShortcutItem(type: "temporary-contact-item",
localizedTitle: "Hiro",
localizedSubtitle: "icon from tmp contact",
icon: temporaryContactIcon,
userInfo: nil)
UIApplication.sharedApplication().shortcutItems = [iconTypeItem, templateItem,
contactStoreContactItem, temporaryContactItem]
28. Handling Quick Actions
public protocol UIApplicationDelegate : NSObjectProtocol {
// …
// Called when the user activates your application by
// selecting a shortcut on the home screen,
// except when -application:willFinishLaunchingWithOptions: or
// -application:didFinishLaunchingWithOptions returns NO.
@available(iOS 9.0, *)
optional public func application(application: UIApplication,
performActionForShortcutItem shortcutItem: UIApplicationShortcutItem,
completionHandler: (Bool) -> Void)
// …
}
29. Handling Quick Actions
public protocol UIApplicationDelegate : NSObjectProtocol {
// …
// Called when the user activates your application by
// selecting a shortcut on the home screen,
// except when -application:willFinishLaunchingWithOptions: or
// -application:didFinishLaunchingWithOptions returns NO.
@available(iOS 9.0, *)
optional public func application(application: UIApplication,
performActionForShortcutItem shortcutItem: UIApplicationShortcutItem,
completionHandler: (Bool) -> Void)
// …
}
Full-blown shortcut item
30. Handling Quick Actions
public protocol UIApplicationDelegate : NSObjectProtocol {
// …
// Called when the user activates your application by
// selecting a shortcut on the home screen,
// except when -application:willFinishLaunchingWithOptions: or
// -application:didFinishLaunchingWithOptions returns NO.
@available(iOS 9.0, *)
optional public func application(application: UIApplication,
performActionForShortcutItem shortcutItem: UIApplicationShortcutItem,
completionHandler: (Bool) -> Void)
// …
}
Call when finished
32. • Press to Peek at what’s inside
• Stop pressing to hide the preview
• Press harder to Pop into the view
Peek and Pop
33. Peek and Pop
extension UIViewController {
// Registers a view controller to participate with 3D Touch preview (peek) and commit (pop).
@available(iOS 9.0, *)
public func registerForPreviewingWithDelegate(delegate: UIViewControllerPreviewingDelegate,
sourceView: UIView) -> UIViewControllerPreviewing
@available(iOS 9.0, *)
public func unregisterForPreviewingWithContext(previewing: UIViewControllerPreviewing)
}
@available(iOS 9.0, *)
public protocol UIViewControllerPreviewingDelegate : NSObjectProtocol {
// 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,
commitViewController viewControllerToCommit: UIViewController)
}
36. Peek and Pop
public protocol UIViewControllerPreviewing : NSObjectProtocol {
// This gesture can be used to cause the previewing presentation
// to wait until one of your gestures fails or to allow simultaneous
// recognition during the initial phase of the preview presentation.
@available(iOS 9.0, *)
public var previewingGestureRecognizerForFailureRelationship: UIGestureRecognizer { get }
@available(iOS 9.0, *)
public var delegate: UIViewControllerPreviewingDelegate { get }
@available(iOS 9.0, *)
public var sourceView: UIView { get }
// This rect will be set to the bounds of sourceView before each call to
// -previewingContext:viewControllerForLocation:
@available(iOS 9.0, *)
public var sourceRect: CGRect { get set }
}
37. Peek and Pop
class ViewController: UIViewController, UIViewControllerPreviewingDelegate {
@IBOutlet weak var sourceView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
registerForPreviewingWithDelegate(self, sourceView: sourceView)
}
func previewingContext(previewingContext: UIViewControllerPreviewing,
viewControllerForLocation location: CGPoint) -> UIViewController? {
let rect = CGRectInset(previewingContext.sourceView.bounds, 20, 20)
previewingContext.sourceRect = rect
return PreviewedViewController()
}
func previewingContext(previewingContext: UIViewControllerPreviewing,
commitViewController viewControllerToCommit: UIViewController) {
navigationController?.pushViewController(viewControllerToCommit,
animated: false)
}
}
44. Detecting 3D Touch
public class UITraitCollection : NSObject, NSCopying, NSSecureCoding {
// …
public var forceTouchCapability: UIForceTouchCapability { get }
// …
}
public enum UIForceTouchCapability : Int {
case Unknown
case Unavailable
case Available
}
45. Detecting 3D Touch
public class UITraitCollection : NSObject, NSCopying, NSSecureCoding {
// …
public var forceTouchCapability: UIForceTouchCapability { get }
// …
}
public enum UIForceTouchCapability : Int {
case Unknown
case Unavailable
case Available
}
/*! Trait environments expose a trait collection that describes their environment. */
public protocol UITraitEnvironment : NSObjectProtocol {
public var traitCollection: UITraitCollection { get }
/*! To be overridden as needed to provide
custom behavior when the environment's traits change. */
public func traitCollectionDidChange(previousTraitCollection: UITraitCollection?)
}
46. Detecting 3D Touch
public class UITraitCollection : NSObject, NSCopying, NSSecureCoding {
// …
public var forceTouchCapability: UIForceTouchCapability { get }
// …
}
public enum UIForceTouchCapability : Int {
case Unknown
case Unavailable
case Available
}
/*! Trait environments expose a trait collection that describes their environment. */
public protocol UITraitEnvironment : NSObjectProtocol {
public var traitCollection: UITraitCollection { get }
/*! To be overridden as needed to provide
custom behavior when the environment's traits change. */
public func traitCollectionDidChange(previousTraitCollection: UITraitCollection?)
}
The following interface classes adopt this protocol:
UIScreen, UIWindow, UIViewController, UIPresentationController, and UIView.