Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/119.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UIImagePickerController编辑视图圆覆盖_Ios_Objective C_Ios7_Uiimagepickercontroller_Cashapelayer - Fatal编程技术网

Ios UIImagePickerController编辑视图圆覆盖

Ios UIImagePickerController编辑视图圆覆盖,ios,objective-c,ios7,uiimagepickercontroller,cashapelayer,Ios,Objective C,Ios7,Uiimagepickercontroller,Cashapelayer,我已经能够实现我一直想要实现的目标,那就是复制iOS内置的圆形照片裁剪器,用于内置联系人应用程序。然而,我一直在努力让我的CAShapeLayers制作正确。我正在尝试制作一个直径为320像素的透明圆,视图的其余部分填充0.9 alpha黑色背景。圆和矩形在正确的位置,但是,圆并不像我需要的那样是完全透明的 我不知道如何解决这个问题。我感谢你的帮助!代码和屏幕截图: - (void)navigationController:(UINavigationController *)navigation

我已经能够实现我一直想要实现的目标,那就是复制iOS内置的圆形照片裁剪器,用于内置联系人应用程序。然而,我一直在努力让我的
CAShapeLayers
制作正确。我正在尝试制作一个直径为320像素的透明圆,视图的其余部分填充0.9 alpha黑色背景。圆和矩形在正确的位置,但是,圆并不像我需要的那样是完全透明的

我不知道如何解决这个问题。我感谢你的帮助!代码和屏幕截图:

- (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];
    }
}
已解析代码:

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

要从摄影机执行此操作,请尝试使用cameraOverlayView并设置自己的视图。不过,这只在从相机中选择时有效,而不是从照片库中选择。

我更改了@aviatorken89的代码,因为它不适用于iPhone 6/6+和iPad。现在,它可以与任何iPhone的屏幕大小兼容,也可以在iPad上使用!在iOS 7和iOS 8上测试

所有这些方法都不是真正可靠的,因为它们基于图像选择器子视图层次结构,当然苹果可以改变它。我已经尽力保护代码,以防止将来的iOS版本可能出现的崩溃

我将尝试根据要点更新我的解决方案:

代码如下:

- (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];
    }
} 
Swift 3版本(也带有圆形编辑层,用于照相机拍摄的照片):


在Jakub Marek的代码中,如果您再次打开相机,则存在持久圆形层的问题

要解决此问题,请在openCamera函数中添加:

editLayer?.removeFromSuperlayer()
label?.removeFromSuperview()
并在专用func hideDefaultEditOverlay中替换(视图:UIView)

代码:

func openCamera(){
    if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerController.SourceType.camera)){
        imagePicker.sourceType = UIImagePickerController.SourceType.camera
        //If you dont want to edit the photo then you can set allowsEditing to false
        imagePicker.allowsEditing = true
        imagePicker.cameraDevice = .rear
        imagePicker.showsCameraControls = true
        imagePicker.cameraCaptureMode = .photo

        imagePicker.delegate = self
        editLayer?.removeFromSuperlayer()
        label?.removeFromSuperview()
        self.present(imagePicker, animated: true, completion: nil)

    }
    else{
        let alert  = UIAlertController(title: NSLocalizedString("Attention",comment:""), message: NSLocalizedString("You don't have any camera",comment:""), preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: NSLocalizedString("OK",comment:""), style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}

private func hideDefaultEditOverlay(view: UIView)
{
    for subview in view.subviews
    {
        if let cropOverlay = NSClassFromString("PLCropOverlayCropView")
        {
            if subview.isKind(of: cropOverlay) {
                subview.removeFromSuperview()
                //subview.isHidden = true
                break
            }
            else {
                hideDefaultEditOverlay(view: subview)
            }
        }
    }
}

您尝试过UIImagePickerController的
cameraOverlayView
属性吗?这不符合我的目的。请阅读原始问题。-(无效)navigationController:(UINavigationController*)navigationController willShowViewController:(UIViewController*)viewController动画:(BOOL)动画也可以用来避免调整大小的延迟。无论如何,做得很好。@“太好了…”这一定是偶然发生的,因为我昨晚刚刚发现了这个方法,哈哈,棒极了,效果非常好,因为从技术上讲,圆圈的边界是正方形的,所以用户永远不会知道。点击“选择”按钮后,如何获得圆形图像?(就像Contacts应用程序使用圆形图像显示选定区域)您是如何移动视图进行裁剪和编辑的?您知道如何对相机执行此操作吗?使用navigationController委托,我可以在使用相机拍照时访问不同的视图和图层([navigationController.viewControllers count]==1),但在编辑图像时无法访问。你知道怎么做吗?谢谢。如何添加cameraoverlayView。请回答我的问题。感谢照片库我们能用什么?当UIImagePickerController出现在弹出框中时,这段代码在iPad2和iPadPro上似乎不起作用。裁剪区域错误。你的主要链接断开了谢谢@Joey。我已经更新了断开的链接(由于我的Github昵称发生了变化)!它在从gallery浏览图像时显示圆形覆盖,而不是在从gallery选择图像后显示。
subview.isHidden = true
subview.removeFromSuperview()
func openCamera(){
    if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerController.SourceType.camera)){
        imagePicker.sourceType = UIImagePickerController.SourceType.camera
        //If you dont want to edit the photo then you can set allowsEditing to false
        imagePicker.allowsEditing = true
        imagePicker.cameraDevice = .rear
        imagePicker.showsCameraControls = true
        imagePicker.cameraCaptureMode = .photo

        imagePicker.delegate = self
        editLayer?.removeFromSuperlayer()
        label?.removeFromSuperview()
        self.present(imagePicker, animated: true, completion: nil)

    }
    else{
        let alert  = UIAlertController(title: NSLocalizedString("Attention",comment:""), message: NSLocalizedString("You don't have any camera",comment:""), preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: NSLocalizedString("OK",comment:""), style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}

private func hideDefaultEditOverlay(view: UIView)
{
    for subview in view.subviews
    {
        if let cropOverlay = NSClassFromString("PLCropOverlayCropView")
        {
            if subview.isKind(of: cropOverlay) {
                subview.removeFromSuperview()
                //subview.isHidden = true
                break
            }
            else {
                hideDefaultEditOverlay(view: subview)
            }
        }
    }
}