Last active
April 16, 2020 14:42
-
-
Save andreacipriani/74ea67db8f17673f1b8b to your computer and use it in GitHub Desktop.
iOS: UIImagePickerController editing view circle overlay
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Credit: I've started by reading this SO question: http://stackoverflow.com/questions/20794187/uiimagepickercontroller-editing-view-circle-overlay-edited | |
Trick to add a circle view on image picker editing to facilitate circular cropping | |
Tested on iPhone4s, iPhone5, iPhone6, iPhone6+, iPad - iOS 7 and iOS 8 - on May 2015 | |
**/ | |
#pragma mark - UINavigationControllerDelegate | |
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated | |
{ | |
if ([navigationController.viewControllers count] == 3 && ([[[[navigationController.viewControllers objectAtIndex:2] class] description] isEqualToString:@"PUUIImageViewController"] || [[[[navigationController.viewControllers objectAtIndex:2] class] description] isEqualToString:@"PLUIImageViewController"])) | |
{ | |
[self addCircleOverlayToImagePicker:viewController]; | |
} | |
} | |
#pragma mark - Circle overlay trick | |
-(void)addCircleOverlayToImagePicker:(UIViewController*)viewController | |
{ | |
UIColor *circleColor = [UIColor clearColor]; | |
UIColor *maskColor = [[UIColor blackColor] colorWithAlphaComponent:0.8]; | |
CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height; | |
CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width; | |
UIView *plCropOverlayCropView; //The default crop view, we wan't to hide it and show our circular one | |
UIView *plCropOverlayBottomBar; //On iPhone is the bar with "cancel" and "choose" button, on Ipad is an Image View with a label saying "Scale and move" | |
//Subviews hirearchy is different in iPad/iPhone: | |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){ | |
plCropOverlayCropView = [viewController.view.subviews objectAtIndex:1]; | |
plCropOverlayBottomBar = [[[[viewController.view subviews] objectAtIndex:1] subviews] objectAtIndex:1]; | |
//Protect against iOS changes... | |
if (! [[[plCropOverlayCropView class] description] isEqualToString:@"PLCropOverlay"]){ | |
DDLogWarn(@"Image Picker with circle overlay: PLCropOverlay not found"); | |
return; | |
} | |
if (! [[[plCropOverlayBottomBar class] description] isEqualToString:@"UIImageView"]){ | |
DDLogWarn(@"Image Picker with circle overlay: PLCropOverlayBottomBar not found"); | |
return; | |
} | |
} | |
else{ | |
plCropOverlayCropView = [[[viewController.view.subviews objectAtIndex:1] subviews] firstObject]; | |
plCropOverlayBottomBar = [[[[viewController.view subviews] objectAtIndex:1] subviews] objectAtIndex:1]; | |
//Protect against iOS changes... | |
if (! [[[plCropOverlayCropView class] description] isEqualToString:@"PLCropOverlayCropView"]){ | |
DDLogWarn(@"Image Picker with circle overlay: PLCropOverlayCropView not found"); | |
return; | |
} | |
if (! [[[plCropOverlayBottomBar class] description] isEqualToString:@"PLCropOverlayBottomBar"]){ | |
DDLogWarn(@"Image Picker with circle overlay: PLCropOverlayBottomBar not found"); | |
return; | |
} | |
} | |
//It seems that everything is ok, we found the CropOverlayCropView and the CropOverlayBottomBar | |
plCropOverlayCropView.hidden = YES; //Hide default CropView | |
CAShapeLayer *circleLayer = [CAShapeLayer layer]; | |
//Center the circleLayer frame: | |
UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0.0f, screenHeight/2 - screenWidth/2, screenWidth, screenWidth)]; | |
circlePath.usesEvenOddFillRule = YES; | |
circleLayer.path = [circlePath CGPath]; | |
circleLayer.fillColor = circleColor.CGColor; | |
//Mask layer frame: it begins on y=0 and ends on y = plCropOverlayBottomBar.origin.y | |
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, screenWidth, screenHeight- plCropOverlayBottomBar.frame.size.height) cornerRadius:0]; | |
[maskPath appendPath:circlePath]; | |
maskPath.usesEvenOddFillRule = YES; | |
CAShapeLayer *maskLayer = [CAShapeLayer layer]; | |
maskLayer.path = maskPath.CGPath; | |
maskLayer.fillRule = kCAFillRuleEvenOdd; | |
maskLayer.fillColor = maskColor.CGColor; | |
[viewController.view.layer addSublayer:maskLayer]; | |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){ | |
//On iPhone add an hint label on top saying "scale and move" or whatever you want | |
UILabel *cropLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, screenWidth, 50)]; | |
[cropLabel setText:NSLocalizedString(@"IMAGE_PICKER_CROP_LABEL", nil)]; | |
[cropLabel setTextAlignment:NSTextAlignmentCenter]; | |
[cropLabel setTextColor:[UIColor whiteColor]]; | |
[viewController.view addSubview:cropLabel]; | |
} | |
else{ //On iPad re-add the overlayBottomBar with the label "scale and move" because we set its parent to hidden (it's a subview of PLCropOverlay) | |
[viewController.view addSubview:plCropOverlayBottomBar]; | |
} | |
} |
great its help me.
it is crash in swift 3.0 but successfully run in objective c in xcode 8.2.1 version.
hi @andreacipriani, @JaDenis, thanks for code, i have problem that, i want to change frame of new overlay, but crop frame not change follow new overlay. Please help me for this case. New overlay of me:
UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(25.0f , screenHeight/2 - screenWidth/2, screenWidth-50, screenWidth-50)];
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
dude, change your "didShowViewController" delegate method to "willShowViewController" - no delay after that 👍
still looking into take Photo with Camera issue...