在imagePicker前面显示一个视图

在我的应用程序中,用户可以打开相机胶卷选择图片或打开相机直接单独拍摄 .

在这两种情况下,所选/拍摄的照片也将保存在本地以供进一步参考 .

缺点是保存操作通常会冻结屏幕直到完成 .

我找到了一个动画in this post,我想在 imagePickerController 前面显示它,但我无法做到 .

class SinglePageViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITextFieldDelegate, UINavigationBarDelegate {


var spinner : UIActivityIndicatorView?
lazy var showCameraImagePickerController: UIImagePickerController  = {
    let imagePicker = UIImagePickerController()
    imagePicker.delegate = self
    imagePicker.sourceType = .camera;
    imagePicker.allowsEditing = false
    return imagePicker
}()
lazy var showPhotoImagePickerController: UIImagePickerController  = {
    let imagePicker = UIImagePickerController()
    imagePicker.delegate = self
    imagePicker.sourceType = .photoLibrary;
    imagePicker.allowsEditing = false
    return imagePicker
}()

@IBOutlet weak var photoButton: UIButton!
@IBAction func onPhotoButton(_ sender: Any) {
    self.present(self.showCameraImagePickerController, animated: true, completion: nil)
}

@IBOutlet weak var galleryButton: UIButton!
@IBAction func onGalleryButton(_ sender: Any) {
    self.present(self.showPhotoImagePickerController, animated: true, completion: nil)

}

 func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    picker.dismiss(animated: true, completion: nil)
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

    //start animation
    let screenSize: CGRect = UIScreen.main.bounds
    spinner = UIActivityIndicatorView(frame: CGRect(x: screenSize.width/2 - 150, y: screenSize.height/2 - 150, width: 300, height: 300))
    spinner?.isHidden = false
    spinner?.startAnimating()
    spinner?.color = UIColor.red

    switch picker {
    case showCameraImagePickerController:
        // snap pic, save to doc, save to album

        self.showCameraImagePickerController.view.addSubview(spinner!)
        timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false, block: {_ in
        let image = info[UIImagePickerControllerOriginalImage] as? UIImage

        if self.saveImage(imageName: "\(self.titleLabel.text!).png", image: image){
            // additionally save to photo album
            UIImageWriteToSavedPhotosAlbum(image!, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
            print("saved \(self.titleLabel.text!).png")
            self.imageView.image = image
        }
        })

    case showPhotoImagePickerController:
        //switch pic, save to doc. no album
        self.showPhotoImagePickerController.view.addSubview(spinner!)

        timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false, block: {_ in
        let image = info[UIImagePickerControllerOriginalImage] as? UIImage

        if self.saveImage(imageName: "\(self.titleLabel.text!).png", image: image){
            print("saved new \(self.titleLabel.text!).png")
            self.imageView.image = image

            self.spinner?.stopAnimating()
            self.spinner?.removeFromSuperview()
            self.spinner  = nil

            self.showPhotoImagePickerController.dismiss(animated: true, completion: nil)

        } else {
            self.spinner?.stopAnimating()
            self.spinner?.removeFromSuperview()
            self.spinner  = nil

            self.showPhotoImagePickerController.dismiss(animated: true, completion: nil)

        }
            })
    default:
        return
    }

}

@objc func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {

    spinner?.stopAnimating()
    spinner?.removeFromSuperview()
    spinner  = nil

    self.showCameraImagePickerController.dismiss(animated: true, completion: nil)

}

func saveImage(imageName: String, image: UIImage?) -> Bool {

    //create an instance of the FileManager
    let fileManager = FileManager.default
    //get the image path
    let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(imgDir+imageName)
    print(imagePath)
    //get the image we took with camera
    let image = rotateImage(image: image!)
    //get the PNG data for this image
    let data = UIImagePNGRepresentation(image)
    //store it in the document directory

    if fileManager.createFile(atPath: imagePath as String, contents: data, attributes: nil){
        newItem?.image = true

        return true
    } else {
        print("error while saving")
        return false
    }
}

你可以看到我尝试使用 bringSubView(toFront:)zPosition 但没有结果 .

以下this similar question我查看了cameraOverlayView的文档,但它说只有当imagePicker以相机模式呈现时它才有效,这不包括我打开照片库时的情况

我最近也尝试使用一种解决方法,这意味着我尽快解除了imagePickerController并在之后更新了图像,但由于app结构的一些变化,这不再是最优的 .

编辑

为了让自己更清楚,我将再次说明我需要的东西:显示imagePicker的微调器动画 in front ,只要我点击一张照片来选择它,直到我完成保存,然后关闭imagePicker . 我想首先解除选择器然后在主视图中显示微调器时保存 .

EDIT2使用答案中的新代码更新了代码 . 唯一的问题是,如果我没有放一个计时器,微调器只会在保存过程结束时显示自己一小段时间(用断点检查) . 这导致在保存过程的几秒钟内没有动画,并且在解除imagePicker之前只是在最后显示微调器 . 只需加一个0.1秒的延迟就会立即触发微调器并获得预期的行为(保存时动画) . 不知道为什么

回答(1)

2 years ago

请参阅一个完整的示例,其中微调器将在保存图像时显示,一旦完成保存,微调器将被删除 .

class ViewController: UIViewController {

    /// Image picker controller
    lazy var imagePickerController: UIImagePickerController  = {
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = .photoLibrary;
        imagePicker.allowsEditing = false
        return imagePicker
    }()

    var spinner: UIActivityIndicatorView?

    @IBAction func imagePickerButton(_ sender: UIButton) {
        self.present(self.imagePickerController, animated: true, completion: nil)
    }
}

// MARK: ImagePicker Delegate to get the image picked by the user
extension ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        //start animation
        let screenSize: CGRect = UIScreen.main.bounds
        spinner = UIActivityIndicatorView(frame: CGRect(x: screenSize.width/2 - 50, y: screenSize.height/2 - 50, width: 100, height: 100))
        spinner?.isHidden = false
        spinner?.startAnimating()
        spinner?.color = UIColor.black
        self.imagePickerController.view.addSubview(spinner!)

        let image = info[UIImagePickerControllerOriginalImage] as? UIImage
        UIImageWriteToSavedPhotosAlbum(image!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)

    }

    @objc func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {

        spinner?.stopAnimating()
        spinner?.removeFromSuperview()
        spinner  = nil

        self.imagePickerController.dismiss(animated: true, completion: nil)

        if  error == nil {
            let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)
            ac.addAction(UIAlertAction(title: "OK", style: .default))
            present(ac, animated: true)
        }
    }

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
}