example ios objective-c ios7 uiimagepickercontroller cashapelayer

ios - example - UIImagePickerController edición vista círculo superposición



uiimagepickercontroller swift 3 (4)

Código resuelto:

- (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]; } }

He podido llegar bastante lejos con lo que quería lograr, y eso es replicar el recortador de fotos circular incorporado de iOS para la aplicación de contactos integrada. Sin embargo, estoy atascado al intentar que mis CAShapeLayers realicen correctamente. Estoy tratando de hacer un círculo transparente de 320 px de diámetro y el resto de la vista con un fondo negro alfa de 0.9. El círculo y el rectángulo están en el lugar correcto, pero, el círculo no es completamente transparente como lo necesito.

Estoy perdido en cuanto a cómo solucionar esto. ¡Aprecio tu ayuda! Código y captura de pantalla:

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { if ([navigationController.viewControllers count] == 3) { CGRect screenRect = [[UIScreen mainScreen] bounds]; CGFloat screenHeight = screenRect.size.height; UIView *plCropOverlay = [[[viewController.view.subviews objectAtIndex:1]subviews] objectAtIndex:0]; plCropOverlay.hidden = YES; CAShapeLayer *circleLayer = [CAShapeLayer layer]; if (screenHeight == 568) { [circleLayer setPosition:CGPointMake(0.0f,124.0f)]; } else { [circleLayer setPosition:CGPointMake(0.0f,80.0f)]; } UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0.0f, 0.0f, 320.0f, 320.0f)]; [circleLayer setPath:[path CGPath]]; [circleLayer setFillColor:[[UIColor whiteColor] CGColor]]; circleLayer.opacity = 0.7f; // Set to 0.7f to show for screenshot purposes; setting to 0.0 would make it invisible and blend in with the below rectangleLayer. CAShapeLayer *rectangleLayer = [CAShapeLayer layer]; UIBezierPath *path2 = [UIBezierPath bezierPathWithRect:CGRectMake(0.0f, 0.0f, 320.0f, screenHeight - 72)]; [rectangleLayer setPath:[path2 CGPath]]; [rectangleLayer setFillColor:[[UIColor blackColor] CGColor]]; [rectangleLayer setOpacity:0.9f]; [rectangleLayer addSublayer:circleLayer]; [[viewController.view layer] addSublayer:rectangleLayer]; 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]; } }


He cambiado el código de @ aviatorken89 porque no funcionaba en iPhone 6/6 + y iPad. ¡Ahora debería funcionar con cualquier tamaño de pantalla de iPhone y también en iPad! Probado en iOS 7 y iOS 8.

Todos estos métodos no son realmente confiables porque se basan en la jerarquía de subvistas del Selector de imágenes y, por supuesto, Apple podría cambiarlo. He intentado proteger el código tanto como pude para evitar posibles bloqueos en futuras versiones de iOS.

Trataré de mantener mi solución actualizada de manera global: https://gist.github.com/andreacipriani/74ea67db8f17673f1b8b

Aquí está el código:

- (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]; } } -(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 overlay view, we wan''t to hide it and show our circular one UIView *plCropOverlayBottomBar; //On iPhone this is the bar with "cancel" and "choose" buttons, on Ipad it''s 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"]){ DLog(@"Warning - Image Picker with circle overlay: PLCropOverlay not found"); return; } if (! [[[plCropOverlayBottomBar class] description] isEqualToString:@"UIImageView"]){ DLog(@"Warning - Image Picker with circle overlay: BottomBar 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:@"Scale and move"]; //You should localize it [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]; } }


Para hacer esto desde la cámara, intente usar cameraOverlayView y configure su propia vista. Eso funcionará solo cuando se selecciona desde la cámara y no la biblioteca de fotos.


Versión Swift 3 (también con capa de edición redondeada para fotos tomadas por cámara):

// 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) } } } }