iOS Custom UIImagePickerController Camera Crop to circle - in preview view

孤街醉人 提交于 2019-12-01 12:59:38

问题


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 photos

If I change [navigationController.viewControllers count] == 3 --> [navigationController.viewControllers count] == 1 works for camera too, but not in next view (preview view where you accept to use the photo)

Someone help me??

-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0) {
    NSLog(@"Camara");
    UIImagePickerController * imagePicker = [[UIImagePickerController alloc] init];
    imagePicker.allowsEditing = YES;
    imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    imagePicker.delegate = self;
    self.isCamera = YES;

    [self presentViewController:imagePicker animated:YES completion:nil];

}else{
    NSLog(@"Carrete");
    UIImagePickerController *imagePickerController = [[UIImagePickerController alloc]init];
    imagePickerController.allowsEditing = YES;
    imagePickerController.delegate = self;
    imagePickerController.sourceType =  UIImagePickerControllerSourceTypePhotoLibrary;
    self.isCamera = NO;
    [self presentViewController:imagePickerController animated:YES completion:nil];
}

}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
if (self.isCamera) {
    if ([navigationController.viewControllers count] == 1)
    {
        CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;

        UIView *plCropOverlay = [[[viewController.view.subviews objectAtIndex:1]subviews] objectAtIndex:0];

        plCropOverlay.hidden = YES;

        int position = 0;

        if (screenHeight == 568)
        {
            position = 124;
        }
        else
        {
            position = 80;
        }

        CAShapeLayer *circleLayer = [CAShapeLayer layer];

        UIBezierPath *path2 = [UIBezierPath bezierPathWithOvalInRect:
                               CGRectMake(0.0f, position, 320.0f, 320.0f)];
        [path2 setUsesEvenOddFillRule:YES];

        [circleLayer setPath:[path2 CGPath]];

        [circleLayer setFillColor:[[UIColor clearColor] CGColor]];
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 320, screenHeight-72) cornerRadius:0];

        [path appendPath:path2];
        [path setUsesEvenOddFillRule:YES];

        CAShapeLayer *fillLayer = [CAShapeLayer layer];
        fillLayer.path = path.CGPath;
        fillLayer.fillRule = kCAFillRuleEvenOdd;
        fillLayer.fillColor = [UIColor blackColor].CGColor;
        fillLayer.opacity = 0.8;
        [viewController.view.layer addSublayer:fillLayer];

        UILabel *moveLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, 320, 50)];
        [moveLabel setText:@"Move and Scale"];
        [moveLabel setTextAlignment:NSTextAlignmentCenter];
        [moveLabel setTextColor:[UIColor whiteColor]];

        [viewController.view addSubview:moveLabel];
    }

}else{
    if ([navigationController.viewControllers count] == 3)
    {
        CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;

        UIView *plCropOverlay = [[[viewController.view.subviews objectAtIndex:1]subviews] objectAtIndex:0];

        plCropOverlay.hidden = YES;

        int position = 0;

        if (screenHeight == 568)
        {
            position = 124;
        }
        else
        {
            position = 80;
        }

        CAShapeLayer *circleLayer = [CAShapeLayer layer];

        UIBezierPath *path2 = [UIBezierPath bezierPathWithOvalInRect:
                               CGRectMake(0.0f, position, 320.0f, 320.0f)];
        [path2 setUsesEvenOddFillRule:YES];

        [circleLayer setPath:[path2 CGPath]];

        [circleLayer setFillColor:[[UIColor clearColor] CGColor]];
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 320, screenHeight-72) cornerRadius:0];

        [path appendPath:path2];
        [path setUsesEvenOddFillRule:YES];

        CAShapeLayer *fillLayer = [CAShapeLayer layer];
        fillLayer.path = path.CGPath;
        fillLayer.fillRule = kCAFillRuleEvenOdd;
        fillLayer.fillColor = [UIColor blackColor].CGColor;
        fillLayer.opacity = 0.8;
        [viewController.view.layer addSublayer:fillLayer];

        UILabel *moveLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, 320, 50)];
        [moveLabel setText:@"Move and Scale"];
        [moveLabel setTextAlignment:NSTextAlignmentCenter];
        [moveLabel setTextColor:[UIColor whiteColor]];

        [viewController.view addSubview:moveLabel];
    }

}

}


回答1:


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:

  1. In order to get overlay working properly on Camera, I was listening to notifications (taken & rejecting picture) due to add or remove circle overlay

  2. 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)
}
}



回答2:


Here is the solution which might help you to create crop overlay:-

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if ([navigationController.viewControllers count] == 3)
    {
        CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;

        UIView *plCropOverlay = [[[viewController.view.subviews objectAtIndex:1]subviews] objectAtIndex:0];

        plCropOverlay.hidden = YES;

        int position = 0;

        if (screenHeight == 568)
        {
            position = 124;
        }
        else
        {
            position = 80;
        }

        CAShapeLayer *circleLayer = [CAShapeLayer layer];

        UIBezierPath *path2 = [UIBezierPath bezierPathWithOvalInRect:
                               CGRectMake(0.0f, position, 320.0f, 320.0f)];
        [path2 setUsesEvenOddFillRule:YES];

        [circleLayer setPath:[path2 CGPath]];

        [circleLayer setFillColor:[[UIColor clearColor] CGColor]];
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 320, screenHeight-72) cornerRadius:0];

        [path appendPath:path2];
        [path setUsesEvenOddFillRule:YES];

        CAShapeLayer *fillLayer = [CAShapeLayer layer];
        fillLayer.path = path.CGPath;
        fillLayer.fillRule = kCAFillRuleEvenOdd;
        fillLayer.fillColor = [UIColor blackColor].CGColor;
        fillLayer.opacity = 0.8;
        [viewController.view.layer addSublayer:fillLayer];

        UILabel *moveLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, 320, 50)];
        [moveLabel setText:@"Move and Scale"];
        [moveLabel setTextAlignment:NSTextAlignmentCenter];
        [moveLabel setTextColor:[UIColor whiteColor]];

        [viewController.view addSubview:moveLabel];
    }
}


来源:https://stackoverflow.com/questions/28365819/ios-custom-uiimagepickercontroller-camera-crop-to-circle-in-preview-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!