iOS Custom UIImagePickerController Camera Crop to circle - 在预览视图中

时间:2015-02-06 12:26:59

标签: ios camera uiimagepickercontroller

我正在使用此代码制作自定义相机裁剪:

UIImagePickerController editing view circle overlay

这在相机胶卷中完美无效,但不拍照

如果我更改[navigationController.viewControllers count] == 3 - > [navigationController.viewControllers count] == 1也适用于相机,但不适用于下一个视图(预览视图,您接受使用该照片)

有人帮助我吗??

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

}

}

4 个答案:

答案 0 :(得分:1)

SwiftUI,Swift 5中的类似解决方案

我为此花费了很长时间,但终于有了一个可行的解决方案。

我用Swift或SwiftUI编写代码已有很长时间了,我绝对欢迎大家提出改进代码的意见。在某些地方,我留下了一些您可以取消注释的调试代码。将我的脑袋缠在数学上比能干的,经过深思熟虑的方法要花更多的尝试和错误!

此代码中的缺点第一,最好从ContentView()打开Impage选择器,然后显示我的自定义视图。我不知道该怎么做。 第二,如果ContentView()中已经有图像,则最好在自定义视图中填充该图像。但是,然后,用户可能希望能够获得“原始”图像并对其进行移动和缩放。这将需要更多的答案。即,您是否要将原始照片保存在某些url /应用程序文件夹中以及裁剪的版本中?甚至保存带有原始图片和重新创建裁剪视图所需的CGRect的字典? 第三。如果所选照片恰好等于屏幕大小(屏幕截图),则似乎存在错误;它可以缩放得太低。

在一个新的SwiftUI生命周期应用程序中,我具有以下SwiftUI视图:

这是您将得到的:

SwiftUI example of photo move and scale app SwiftUI circlemask screen for photo selection ImagePicker UIRepresentable in SwiftUI Selected Image in SwiftUI view Scaled Image in custom SwiftUI view Saved cropped and scqaled image for contact image

我还使用这种至关重要的解决方案进行裁剪:

  • ImageManipulation.swift

最后,我的一些代码访问系统UIcolors,所以我在其中使用扩展名

  • Colors.swift

ContentView

    import SwiftUI
    
    struct ContentView: View {
        
        @State private var isShowingPhotoSelectionSheet = false

        @State private var finalImage: UIImage?
        @State private var inputImage: UIImage?
        
        var body: some View {
            
            VStack {
                
                if finalImage != nil {
                    Image(uiImage: finalImage!)
                        .resizable()
                        .frame(width: 100, height: 100)
                        .scaledToFill()
                        .aspectRatio(contentMode: .fit)
                        .clipShape(Circle())
                        .shadow(radius: 4)
                } else {
                    Image(systemName: "person.crop.circle.fill")
                        .resizable()
                        .scaledToFill()
                        .frame(width: 100, height: 100)
                        .aspectRatio(contentMode: .fit)
                        .foregroundColor(.systemGray2)
                }
                Button (action: {
                    self.isShowingPhotoSelectionSheet = true
                }, label: {
                    Text("Change photo")
                        .foregroundColor(.systemRed)
                        .font(.footnote)
                })
            }
            .background(Color.systemBackground)
            .statusBar(hidden: isShowingPhotoSelectionSheet)
            .fullScreenCover(isPresented: $isShowingPhotoSelectionSheet, onDismiss: loadImage) {
                ImageMoveAndScaleSheet(croppedImage: $finalImage)
            }
        }
        
        func loadImage() {
            guard let inputImage = inputImage else { return }
            finalImage = inputImage
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }

Change photo上单击/点击会弹出下一个视图:

ImagemoveAndScaleSheet

这是一个全屏模式,在打开时会隐藏状态栏。

    import SwiftUI
    
    struct ImageMoveAndScaleSheet: View {
        
        @Environment(\.presentationMode) var presentationMode
        
        @State private var isShowingImagePicker = false

        ///The croped image is what will will send back to the parent view.
        ///It should be the part of the image in the square defined by the
        ///cutout circle's diamter. See below, the cutout circle has an "inset" value
        ///which can be changed.
        @Binding var croppedImage: UIImage?

        ///The input image is received from the ImagePicker.
        ///We will need to calculate and refer to its aspectr ratio in the functions.
        @State private var inputImage: UIImage?
        @State private var inputW: CGFloat = 750.5556577
        @State private var inputH: CGFloat = 1336.5556577
        
        @State private var theAspectRatio: CGFloat = 0.0

        ///The profileImage is what wee see on this view. When added from the
        ///ImapgePicker, it will be sized to fit the screen,
        ///meaning either its width will match the width of the device's screen,
        ///or its height will match the height of the device screen.
        ///This is not suitable for landscape mode or for iPads.
        @State private var profileImage: Image?
        @State private var profileW: CGFloat = 0.0
        @State private var profileH: CGFloat = 0.0
        
        ///Zoom and Drag ...
        @State private var currentAmount: CGFloat = 0
        @State private var finalAmount: CGFloat = 1
        
        @State private var currentPosition: CGSize = .zero
        @State private var newPosition: CGSize = .zero
        
        ///We track of amount the image is moved for use in functions below.
        @State private var horizontalOffset: CGFloat = 0.0
        @State private var verticalOffset: CGFloat = 0.0
        
        var body: some View {
            
            ZStack {
                ZStack {
                    Color.black.opacity(0.8)
                    if profileImage != nil {
                        profileImage?
                            .resizable()
                            .scaleEffect(finalAmount + currentAmount)
                            .scaledToFill()
                            .aspectRatio(contentMode: .fit)
                            .offset(x: self.currentPosition.width, y: self.currentPosition.height)
                    } else {
                        Image(systemName: "person.crop.circle.fill")
                            .resizable()
                            .scaleEffect(finalAmount + currentAmount)
                            .scaledToFill()
                            .aspectRatio(contentMode: .fit)
                            .foregroundColor(.systemGray2)
                    }
                }
                Rectangle()
                    .fill(Color.black).opacity(0.55)
                    .mask(HoleShapeMask().fill(style: FillStyle(eoFill: true)))
                VStack {
                    Text((profileImage != nil) ? "Move and Scale" : "Select a Photo by tapping the icon below")
                        .foregroundColor(.white)
                        .padding(.top, 50)
                    Spacer()
                    HStack{
                        ZStack {
                            HStack {
                                Button(
                                    action: {presentationMode.wrappedValue.dismiss()},
                                    label: { Text("Cancel") })
                                Spacer()
                                Button(
                                    action: {
                                        self.save()
                                        presentationMode.wrappedValue.dismiss()
                                        
                                    })
                                    { Text("Save") }
                                    .opacity((profileImage != nil) ? 1.0 : 0.2)
                                    .disabled((profileImage != nil) ? false: true)
                                    
                            }
                            .padding(.horizontal)
                            .foregroundColor(.white)
                            Image(systemName: "circle.fill")
                                .font(.custom("system", size: 45))
                                .opacity(0.9)
                                .foregroundColor(.white)
                            Image(systemName: "photo.on.rectangle")
                                .imageScale(.medium)
                                .foregroundColor(.black)
                                .onTapGesture {
                                    isShowingImagePicker = true
                                }
                        }
                        .padding(.bottom, 5)
                    }
                }
                .padding()
            }
            .edgesIgnoringSafeArea(.all)
            
            //MARK: - Gestures
            
            .gesture(
                MagnificationGesture()
                    .onChanged { amount in
                        self.currentAmount = amount - 1
                        //                    repositionImage()
                    }
                    .onEnded { amount in
                        self.finalAmount += self.currentAmount
                        self.currentAmount = 0
                        repositionImage()
                    }
            )
            .simultaneousGesture(
                DragGesture()
                    .onChanged { value in
                        self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)
                    }
                    .onEnded { value in
                        self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height)
                        self.newPosition = self.currentPosition
                        repositionImage()
                    }
            )
            .simultaneousGesture(
                TapGesture(count: 2)
                    .onEnded({
                        resetImageOriginAndScale()
                    })
            )
            .sheet(isPresented: $isShowingImagePicker, onDismiss: loadImage) {
                ImagePicker(image: self.$inputImage)
                    .accentColor(Color.systemRed)
            }
        }
        
        //MARK: - functions
        
        private func HoleShapeMask() -> Path {
            let rect = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
            let insetRect = CGRect(x: inset, y: inset, width: UIScreen.main.bounds.width - ( inset * 2 ), height: UIScreen.main.bounds.height - ( inset * 2 ))
            var shape = Rectangle().path(in: rect)
            shape.addPath(Circle().path(in: insetRect))
            return shape
        }
        
        ///Called when the ImagePicker is dismissed.
        ///We want to measure the image receoived and determine the aspect ratio.
        
        private func loadImage() {
            guard let inputImage = inputImage else { return }
            let w = inputImage.size.width
            let h = inputImage.size.height
            profileImage = Image(uiImage: inputImage)
            
            inputW = w
            inputH = h
            theAspectRatio = w / h
            
            resetImageOriginAndScale()
        }
        
        ///The profileImage will size to fit the screen.
        ///But we need to know the width and height
        ///to set the related @State variables.
        ///Douobke-tpping the image will also set it
        ///as it was sized originally upon loading.
        private func resetImageOriginAndScale() {
            withAnimation(.easeInOut){
                if theAspectRatio >= screenAspect {
                    profileW = UIScreen.main.bounds.width
                    profileH = profileW / theAspectRatio
                } else {
                    profileH = UIScreen.main.bounds.height
                    profileW = profileH * theAspectRatio
                }
                currentAmount = 0
                finalAmount = 1
                currentPosition = .zero
                newPosition = .zero
            }
        }
        
        
        private func repositionImage() {
            
            //Screen width
            let w = UIScreen.main.bounds.width
            
            if theAspectRatio > screenAspect {
                profileW = UIScreen.main.bounds.width * finalAmount
                profileH = profileW / theAspectRatio
            } else {
                profileH = UIScreen.main.bounds.height * finalAmount
                profileW = profileH * theAspectRatio
            }

            horizontalOffset = (profileW - w ) / 2
            verticalOffset = ( profileH - w ) / 2
            
            
            ///Keep the user from zooming too far in. Adjust as required by the individual project.
            if finalAmount > 4.0 {
                withAnimation{
                    finalAmount = 4.0
                }
            }
            
            ///The following if statements keep the image filling the circle cutout.
            if profileW >= UIScreen.main.bounds.width {
                
                if newPosition.width > horizontalOffset {
                    withAnimation(.easeInOut) {
                        newPosition = CGSize(width: horizontalOffset + inset, height: newPosition.height)
                        currentPosition = CGSize(width: horizontalOffset + inset, height: currentPosition.height)
                    }
                }
                
                if newPosition.width < ( horizontalOffset * -1) {
                    withAnimation(.easeInOut){
                        newPosition = CGSize(width: ( horizontalOffset * -1) - inset, height: newPosition.height)
                        currentPosition = CGSize(width: ( horizontalOffset * -1 - inset), height: currentPosition.height)
                    }
                }
            } else {
                
                withAnimation(.easeInOut) {
                    newPosition = CGSize(width: 0, height: newPosition.height)
                    currentPosition = CGSize(width: 0, height: newPosition.height)
                }
            }
            
            if profileH >= UIScreen.main.bounds.width {
                
                if newPosition.height > verticalOffset {
                    withAnimation(.easeInOut){
                        newPosition = CGSize(width: newPosition.width, height: verticalOffset + inset)
                        currentPosition = CGSize(width: newPosition.width, height: verticalOffset + inset)
                    }
                }
                
                if newPosition.height < ( verticalOffset * -1) {
                    withAnimation(.easeInOut){
                        newPosition = CGSize(width: newPosition.width, height: ( verticalOffset * -1) - inset)
                        currentPosition = CGSize(width: newPosition.width, height: ( verticalOffset * -1) - inset)
                    }
                }
            } else {
                
                withAnimation (.easeInOut){
                    newPosition = CGSize(width: newPosition.width, height: 0)
                    currentPosition = CGSize(width: newPosition.width, height: 0)
                }
            }
            
            if profileW <= UIScreen.main.bounds.width && theAspectRatio > screenAspect {
                resetImageOriginAndScale()
            }
            if profileH <= UIScreen.main.bounds.height && theAspectRatio < screenAspect {
                resetImageOriginAndScale()
            }
        }
        
        private func save() {
            
            let scale = (inputImage?.size.width)! / profileW
            
            let xPos = ( ( ( profileW - UIScreen.main.bounds.width ) / 2 ) + inset + ( currentPosition.width * -1 ) ) * scale
            let yPos = ( ( ( profileH - UIScreen.main.bounds.width ) / 2 ) + inset + ( currentPosition.height * -1 ) ) * scale
            let radius = ( UIScreen.main.bounds.width - inset * 2 ) * scale
            
            croppedImage = imageWithImage(image: inputImage!, croppedTo: CGRect(x: xPos, y: yPos, width: radius, height: radius))
            
            ///Debug maths
            print("Input: w \(inputW) h \(inputH)")
            print("Profile: w \(profileW) h \(profileH)")
            print("X Origin: \( ( ( profileW - UIScreen.main.bounds.width - inset ) / 2 ) + ( currentPosition.width  * -1 ) )")
            print("Y Origin: \( ( ( profileH - UIScreen.main.bounds.width - inset) / 2 ) + ( currentPosition.height  * -1 ) )")
            
            print("Scale: \(scale)")
            print("Profile:\(profileW) + \(profileH)" )
            print("Curent Pos: \(currentPosition.debugDescription)")
            print("Radius: \(radius)")
            print("x:\(xPos), y:\(yPos)")
        }
        
        let inset: CGFloat = 15
        let screenAspect = UIScreen.main.bounds.width / UIScreen.main.bounds.height
    }

除了拖动和缩放手势外,主要功能是外观和(可能还需要清理!)。

  • HoleShapeMask()(不记得该代码在哪里,但我知道我在SO上得到它。
  • repositionImage()(在这里大摇大摆)
  • save(),它使用ImageManipulation.swift文件中的功能。

ImagePicker

同样,这只是来自Hacking With Swift。 (谢谢保罗!)https://twitter.com/twostraws/

    import SwiftUI

    struct ImagePicker: UIViewControllerRepresentable {
        
        @Environment(\.presentationMode) var presentationMode
        @Binding var image: UIImage?
        
        class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
            let parent: ImagePicker
            
            init(_ parent: ImagePicker) {
                self.parent = parent
            }
            
            func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
                if let uiImage = info[.originalImage] as? UIImage {
                    parent.image = uiImage
                }
                parent.presentationMode.wrappedValue.dismiss()
            }
        }

        func makeCoordinator() -> Coordinator {
            Coordinator(self)
        }
        
        func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
            let picker = UIImagePickerController()
            picker.delegate = context.coordinator
            return picker
        }

        func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {

        }
    }

ImageManipulation.swift

其中包含以下代码:

    import UIKit

    func imageWithImage(image: UIImage, croppedTo rect: CGRect) -> UIImage {

        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()

        let drawRect = CGRect(x: -rect.origin.x, y: -rect.origin.y,
                              width: image.size.width, height: image.size.height)

        context?.clip(to: CGRect(x: 0, y: 0,
                                 width: rect.size.width, height: rect.size.height))

        image.draw(in: drawRect)

        let subImage = UIGraphicsGetImageFromCurrentImageContext()

        UIGraphicsEndImageContext()
        return subImage!
    }

## Colors.swift ##

A handy extension to access system UIColors in SwiftUI:

    import Foundation
    import SwiftUI

    extension Color {

        static var label: Color {
            return Color(UIColor.label)
        }

        static var secondaryLabel: Color {
            return Color(UIColor.secondaryLabel)
        }

        static var tertiaryLabel: Color {
            return Color(UIColor.tertiaryLabel)
        }

        static var quaternaryLabel: Color {
            return Color(UIColor.quaternaryLabel)
        }

        static var systemFill: Color {
            return Color(UIColor.systemFill)
        }

        static var secondarySystemFill: Color {
            return Color(UIColor.secondarySystemFill)
        }

        static var tertiarySystemFill: Color {
            return Color(UIColor.tertiarySystemFill)
        }

        static var quaternarySystemFill: Color {
            return Color(UIColor.quaternarySystemFill)
        }

        static var systemBackground: Color {
               return Color(UIColor.systemBackground)
        }

        static var secondarySystemBackground: Color {
            return Color(UIColor.secondarySystemBackground)
        }

        static var tertiarySystemBackground: Color {
            return Color(UIColor.tertiarySystemBackground)
        }

        static var systemGroupedBackground: Color {
            return Color(UIColor.systemGroupedBackground)
        }

        static var secondarySystemGroupedBackground: Color {
            return Color(UIColor.secondarySystemGroupedBackground)
        }

        static var tertiarySystemGroupedBackground: Color {
            return Color(UIColor.tertiarySystemGroupedBackground)
        }

        static var systemRed: Color {
            return Color(UIColor.systemRed)
        }

        static var systemBlue: Color {
            return Color(UIColor.systemBlue)
        }

        static var systemPink: Color {
            return Color(UIColor.systemPink)
        }

        static var systemTeal: Color {
            return Color(UIColor.systemTeal)
        }

        static var systemGreen: Color {
            return Color(UIColor.systemGreen)
        }

        static var systemIndigo: Color {
            return Color(UIColor.systemIndigo)
        }

        static var systemOrange: Color {
            return Color(UIColor.systemOrange)
        }

        static var systemPurple: Color {
            return Color(UIColor.systemPurple)
        }

        static var systemYellow: Color {
            return Color(UIColor.systemYellow)
        }

        static var systemGray: Color {
            return Color(UIColor.systemGray)
        }

        static var systemGray2: Color {
            return Color(UIColor.systemGray2)
        }

        static var systemGray3: Color {
            return Color(UIColor.systemGray3)
        }

        static var systemGray4: Color {
            return Color(UIColor.systemGray4)
        }

        static var systemGray5: Color {
            return Color(UIColor.systemGray5)
        }

        static var systemGray6: Color {
            return Color(UIColor.systemGray6)
        }
        
    }


答案 1 :(得分:0)

虽然我认为我的回复可能为时已晚,但我最终将我的解决方案与此问题混合起来:https://gist.github.com/hamin/e8c6dfe00d9c81375f3e,其中:

  1. 为了让相机上的叠加层正常工作,我正在收听由于添加或删除圆圈叠加而导致的通知(拍摄和拒绝图片)

  2. 保持上面提到的解决方案,我需要循环通过UINavigationController并在请求时绘制圆形叠加。

  3. 总结一下,请在下面找到我用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 :(得分:0)

以下是可帮助您创建裁剪叠加层的解决方案: -

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

答案 3 :(得分:0)

extension ProfileViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
    guard imagePickerController?.sourceType == .camera else {
        return
    }

    guard let view = viewController.view.subviews(deep: true, where: {
        String(describing: type(of:$0)) == "CAMPreviewView"
    }).first else {
        return
    }

    viewController.view.layoutIfNeeded()

    let camPreviewBounds = view.bounds
    let circleRect = CGRect(
        x: camPreviewBounds.minX + (camPreviewBounds.width - 320) * 0.5,
        y: camPreviewBounds.minY + (camPreviewBounds.height - 320) * 0.5,
        width: 320,
        height: 320
    )

    let path = UIBezierPath(roundedRect: camPreviewBounds, cornerRadius: 0)
    path.append(UIBezierPath(ovalIn: circleRect))

    let layer = CAShapeLayer()
    layer.path = path.cgPath
    layer.fillRule = CAShapeLayerFillRule.evenOdd;
    layer.fillColor = UIColor.black.cgColor
    layer.opacity = 0.8;

    view.layer.addSublayer(layer)
}
}