Wrapper for 3D touch preview implementation using Swift 3.0
It's been a while since I started working on 3D touch implementation on iOS 6s Plus devices. Luckily, even through it's a hardware feature iOS simulators still supports simulation of 3D touch of supported devices. I wrote a sample project demonstrating the use of 3D touch along with blog post accompanying this project.
However, I have been thinking about this - Can we hide implementation details to end user so that they don't have to know all about 3D touch code? The product of my thinking was a project for providing wrapper for implementing 3D touch in iOS apps. Although I feel like it is doing pretty much what it is supposed to do given the fairly understandable documentation, I have a strong feeling that it can still do better. However, for this blog post I am going to assume the version 0.0.1 which as been recently released on the Github.
Please note that in order to successfully run this project, you have to run it in the 3D touch enabled device or simulator. I hope documentation below is clear enough to understand. If there is any ambiguity or unclear part, please do refer to the sample project demo inside main library or you can even contact me directly with any question you might have.
-
Adding library to the client app
In order to start using 3D touch wrapper, all you can to do is that drag and drop following two files from
source
directory located under root inside your project.Touch3DPreviewViewController.swift
Touch3DWrapperProtocol.swift
-
Register for 3D touch
To use 3D touch, a UIViewController
subclass must register for 3D touch on a given view
. In order to do so, you must call registerFor3DTouch
method from UIViewController
's lifestyle method named viewDidLoad
. Also, make sure the viewController where you are planning to present 3D preview from conforms to 3D previewing protocol UIViewControllerPreviewingDelegate
before making call to registerFor3DTouch
.
- Conformance to
Touch3DRecognizerProtocol
Next step is to make UIViewController
subclass to conform to protocol Touch3DRecognizerProtocol
and implement following two protocol methods.
-
func actionItems() -> [UIPreviewActionItem]
Returns the action items associated with 3D touch previewing
viewController
. It could be any number of items where you can declare any arbitrary items and pass them during initialization ofTouch3DPreviewViewController
object -
func locationFrom(point: CGPoint, in view: UIScrollView) -> CGPoint
Takes the touch point as an input and returns the point position relative to
scrollView
ortableView
.This method comes handy when user starts 3D touch on the
tableView
/collectionView
cell and we want to get relative position of touch point relative to thescrollView
in which cell is located.
The following method gets called when user begins 3D touch on
scrollView
cell.
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?
-
Implementing
UIViewControllerPreviewingDelegate
methodsAfter
UIViewController
conforms toUIViewControllerPreviewingDelegate
protocol, it requires to implement following two delegate methods.-
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?
This is a delegate method which gets called after user begins 3D touch on any cell of either
tableView
orcollectionView
. Assuming, client has conformed toTouch3DRecognizerProtocol
and implementedfunc locationFrom(point: CGPoint, in view: UIScrollView) -> CGPoint
method, we can get relative touch position by callinglocationFrom
method passing touch point andscrollView
subclass.Once we get relative touch point, next few things are left to client to calculate to pass to
Touch3DPreviewViewController
initializer. -
informationObject
This is an object which gets passed from current
viewController
topreviewViewController
and then to final destinationviewController
. In order to simplify implementation, this could be object ofAny
type -
touchPreviewActionItems
This is the collection of preview items which accompany the options presented to user on
previewViewController
. User can pass them by calling implementation offunc actionItems() -> [UIPreviewActionItem]
which is the part ofTouch3DRecognizerProtocol
protocol -
thumbnailImage
This is a thumbnail image which is passed to
previewViewController
and is presented as a part of preview of selected choice
-
-
After we calculate 3 items mentioned in previous point, we can initialize our
Touch3DPreviewViewController
and return it
let previewViewController = Touch3DPreviewViewController(informationObject: selectedPlayerNameString, touchPreviewActionItems: self.actionItems(), thumbnailImage: thumbnailImage)
return previewViewController
Also, make sure to provide following check in the beginning of this method in order to prevent Touch3DPreviewViewController
from being displayed multiple times
if let _ = self.presentedViewController as? Touch3DPreviewViewController {
return nil
}
If any on the desired condition is not satisfied, you can simply return nil
from the method.
-
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController)
This is the second and final mandatory method client app should implement as a part of
UIViewControllerPreviewingDelegate
protocol. This method is called when user has applied enough force to make transition from currentviewController
to directly destinationviewController
dismissingpreviewViewController
. In this method, you can grab theinformationObject
passed toTouch3DPreviewViewController
as mentioned in previous point.
Once we get hold of informationObject
, it can be cast into any custom type and can be further passed to destination viewController
in the form of property as follows,
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
if let previewVC = viewControllerToCommit as? Touch3DPreviewViewController {
if let imageName = previewVC.informationObject as? [implementation-specific-inbuilt-or-custom-object-type] {
// Beginning of sample code - Please replace it with your own implementation
if let imageViewController = self.storyboard?.instantiateViewController(withIdentifier: "image") as? ImageViewController {
imageViewController.imageName = imageName
let navController = UINavigationController(rootViewController: imageViewController)
self.present(navController, animated: true, completion: nil)
}
// End of Sample code
}
}
}
Where ImageViewController
is your dummy destination viewController
which you want to make transition to.
Please refer to demo project added to library. I am working on getting rid of code which makes client to implement certain parts of preview implementation. I did it to offer extra flexibility and avoid pressing too much implementation constraints on the client side. If you have any suggestions on further improvement, please let me know