I\'m using this code to make a custom camera crop:
UIImagePickerController editing view circle overlay
This works perfectly in camera roll but not taking pho
Although I believe that my reply might be too late, I ended it up mixing my solution with this one: https://gist.github.com/hamin/e8c6dfe00d9c81375f3e, where:
In order to get overlay working properly on Camera, I was listening to notifications (taken & rejecting picture) due to add or remove circle overlay
Kept the solution mentioned above where I need to loop through UINavigationController and draw circle overlay when it was requested to.
To sum up, please find below my solution written in Swift:
public class CustomPicture: NSObject {
//MARK: - Properties
private var myPickerController: UIImagePickerController?
private var plCropOverlayBottomBar: UIView?
private var customLayer: CAShapeLayer?
//MARK: - Constants
private let screenHeight = UIScreen.mainScreen().bounds.size.height
private let screenWidth = UIScreen.mainScreen().bounds.size.width
private let kCameraNotificationIrisAnimationEnd = "_UIImagePickerControllerUserDidCaptureItem"
private let kCameraNotificationUserRejection = "_UIImagePickerControllerUserDidRejectItem"
private let kPUUIImageViewController = "PUUIImageViewController"
private let kPLUIImageViewController = "PLUIImageViewController"
private let kPLCropOverlayCropView = "PLCropOverlayCropView"
private let kPLCropOverlayBottomBar = "PLCropOverlayBottomBar"
//MARK: - Overrides
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
//MARK: - Privates
private func camera() {
listenToCameraNotifications()
let myPickerController = UIImagePickerController()
myPickerController.delegate = self
myPickerController.sourceType = .Camera
myPickerController.allowsEditing = true
self.myPickerController = myPickerController
self.navigationController?.presentViewController(myPickerController, animated: true, completion: nil)
}
private func listenToCameraNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(cameraNotificationIrisEnd), name: kCameraNotificationIrisAnimationEnd, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(cameraNotificationRejected), name: kCameraNotificationUserRejection, object: nil)
}
private func photoLibrary() {
let myPickerController = UIImagePickerController()
myPickerController.delegate = self
myPickerController.allowsEditing = true
myPickerController.sourceType = .PhotoLibrary
self.myPickerController = myPickerController
self.navigationController?.presentViewController(myPickerController, animated: true, completion: nil)
}
//MARK: - Selector
/**
Listen to notification sent after reject button has been touched
*/
func cameraNotificationRejected() {
customLayer!.removeFromSuperlayer()
plCropOverlayBottomBar!.removeFromSuperview()
}
/**
Listen to notification sent after picture has been taken
*/
func cameraNotificationIrisEnd() {
addCircleOverlay(viewController: self.myPickerController!)
}
}
extension CustomPicture: UINavigationControllerDelegate {
//MARK: - Override
public func navigationController(navigationController: UINavigationController, willShowViewController: UIViewController, animated: Bool) {
if isImageViewer(navigationController: navigationController) {
addCircleOverlay(viewController: willShowViewController)
}
}
//MARK: - Private
private func addCircleOverlay(viewController viewController: UIViewController) {
hidePLCropOverlay(view: viewController.view)
setPLCropOverlayBottomBar(view: viewController.view)
setCustomLayer(viewController: viewController)
}
private func getCirclePath() -> UIBezierPath {
let circlePath = UIBezierPath(ovalInRect: CGRectMake(0, screenHeight / 2 - screenWidth / 2, screenWidth, screenWidth))
circlePath.usesEvenOddFillRule = true
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.CGPath
circleLayer.fillColor = UIColor.clearColor().CGColor
return circlePath
}
private func getMaskPath(screenWidth screenWidth: CGFloat, screenHeight: CGFloat, circlePath: UIBezierPath) -> UIBezierPath {
let maskPath = UIBezierPath(roundedRect: CGRectMake(0, 0, screenWidth, screenHeight), cornerRadius: 0)
maskPath.appendPath(circlePath)
maskPath.usesEvenOddFillRule = true
return maskPath
}
private func hidePLCropOverlay(view view: UIView) {
for myView in view.subviews {
if myView.isKindOfClass(NSClassFromString(kPLCropOverlayCropView)!) {
myView.hidden = true
break
} else {
hidePLCropOverlay(view: myView as UIView)
}
}
}
private func isImageViewer(navigationController navigationController: UINavigationController) -> Bool {
if (navigationController.viewControllers.count == 3 &&
(navigationController.viewControllers[2].dynamicType.description() == kPUUIImageViewController ||
navigationController.viewControllers[2].dynamicType.description() == kPLUIImageViewController)) {
return true
}
return false
}
private func setPLCropOverlayBottomBar(view view: UIView) {
for myView in view.subviews {
if myView.isKindOfClass(NSClassFromString(kPLCropOverlayBottomBar)!) {
plCropOverlayBottomBar = myView
break
}
else {
savePLCropOverlayBottomBar(view: myView as UIView)
}
}
}
private func setCustomLayer(viewController viewController: UIViewController) {
let circlePath = getCirclePath()
let maskPath = getMaskPath(screenWidth: screenWidth, screenHeight: screenHeight, circlePath: circlePath)
let maskLayer = CAShapeLayer()
maskLayer.path = maskPath.CGPath
maskLayer.fillRule = kCAFillRuleEvenOdd
maskLayer.fillColor = UIColor.blackColor().colorWithAlphaComponent(0.8).CGColor
customLayer = maskLayer
viewController.view.layer.addSublayer(customLayer!)
viewController.view.addSubview(plCropOverlayBottomBar!) // put back overlayBottomBar once we set its parent to hidden (subview of PLCropOverlay)
}
}