I\'ve been able to get pretty far with what I\'ve been wanting to accomplish, and that\'s to replicate iOS\'s built in circular photo cropper for the built in contacts app.
Swift 3 version (also with rounded edit layer for pictures taken by camera):
// Insert this code to your view controller
private var editLayer: CAShapeLayer!
private var label: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
// Rounded edit layer
navigationController?.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(pictureCaptured), name: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidCaptureItem"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(pictureRejected), name: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidRejectItem"), object: nil)
}
@objc private func pictureCaptured()
{
addRoundedEditLayer(to: ...your UIImagePickerController..., forCamera: true)
}
@objc private func pictureRejected()
{
editLayer.removeFromSuperlayer()
label.removeFromSuperview()
}
deinit
{
NotificationCenter.default.removeObserver(self)
}
// MARK: Navigation controller delegate
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool)
{
// Image picker in edit mode
if let imageVC = NSClassFromString("PUUIImageViewController")
{
if viewController.isKind(of: imageVC) {
addRoundedEditLayer(to: viewController, forCamera: false)
}
}
}
private func addRoundedEditLayer(to viewController: UIViewController, forCamera: Bool)
{
hideDefaultEditOverlay(view: viewController.view)
// Circle in edit layer - y position
let bottomBarHeight: CGFloat = 72.0
let position = (forCamera) ? viewController.view.center.y - viewController.view.center.x - bottomBarHeight/2 : viewController.view.center.y - viewController.view.center.x
let viewWidth = viewController.view.frame.width
let viewHeight = viewController.view.frame.height
let emptyShapePath = UIBezierPath(ovalIn: CGRect(x: 0, y: position, width: viewWidth, height: viewWidth))
emptyShapePath.usesEvenOddFillRule = true
let filledShapePath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight - bottomBarHeight), cornerRadius: 0)
filledShapePath.append(emptyShapePath)
filledShapePath.usesEvenOddFillRule = true
editLayer = CAShapeLayer()
editLayer.path = filledShapePath.cgPath
editLayer.fillRule = kCAFillRuleEvenOdd
editLayer.fillColor = UIColor.black.cgColor
editLayer.opacity = 0.5
viewController.view.layer.addSublayer(editLayer)
// Move and Scale label
label = UILabel(frame: CGRect(x: 0, y: 10, width: viewWidth, height: 50))
label.text = "Move and Scale"
label.textAlignment = .center
label.textColor = UIColor.white
viewController.view.addSubview(label)
}
private func hideDefaultEditOverlay(view: UIView)
{
for subview in view.subviews
{
if let cropOverlay = NSClassFromString("PLCropOverlayCropView")
{
if subview.isKind(of: cropOverlay) {
subview.isHidden = true
break
}
else {
hideDefaultEditOverlay(view: subview)
}
}
}
}