在 imagePicker 前面显示一个视图

Posted

技术标签:

【中文标题】在 imagePicker 前面显示一个视图【英文标题】:Show a view in front of the imagePicker 【发布时间】:2018-05-15 06:39:45 【问题描述】:

在我的应用程序中,用户可以打开相机胶卷选择一张照片,也可以打开相机自己直接拍照。

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

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

我找到了一个动画 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 并在之后更新图像,但这不再是最佳选择,因为应用程序的结构发生了一些变化。

编辑

为了让自己更清楚,我将再次说明我需要什么:在图像选择器前面显示微调器动画,只要我点击一张照片以选择它,直到我完成保存,然后关闭 imagePicker。 我不想想先关闭选择器,然后在主视图中显示微调器时保存。

EDIT2 用答案中的新代码更新了代码。唯一的问题是,如果我不设置计时器,则微调器只会在保存过程结束时短暂显示(用断点检查)。 这导致在保存过程的几秒钟内没有动画,并且在关闭 imagePicker 之前,最后旋转器的短暂幻影。 只需延迟 0.1 秒就会立即触发微调器,我会得到预期的行为(保存时的动画)。 不知道为什么

【问题讨论】:

代码看起来不错。尝试将backgroundColor 设置为spinnerView 并检查它在DebugViewHierarchy 中的位置。 我能够验证 spinnerView 已创建。如果我在成功保存时不删除它,当 imagePicker 关闭时我可以看到它。只需将它移到前面 嗨@Kamran 很抱歉打扰你,但你知道如何解决我的问题吗?我会提供赏金,但我的积分太少了.. 让我试试。微调器类与另一个问题中的相同? 其实我改成了更简单的mySpinner = UIActivityIndicatorView(frame: CGRect(x: screenSize.width/2 - 50, y: screenSize.height/2 - 50, width: 100, height: 100)) mySpinner?.isHidden = false mySpinner?.startAnimating() mySpinner?.color = UIColor.black self.view.addSubview(mySpinner!) 【参考方案1】:

请查看完整示例,其中在保存图像时将显示微调器,一旦完成保存,微调器将被删除。

    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)
    

【讨论】:

我尝试合并您的一些代码,但现在我什至无法在视图层次结构中看到微调器了。你为什么这样做DispatchQueue.main.async self.navigationController?.present(imagePicker, animated: true, completion: nil) ?我只是这样介绍它@IBAction func onGalleryButton(_ sender: Any) showImagePickerController = UIImagePickerController() showImagePickerController.delegate = self showImagePickerController.allowsEditing = false showImagePickerController.sourceType = .photoLibrary present(showImagePickerController, animated: true, completion: nil) @MaX 虽然这段代码运行良好,但你仍然面临这个问题,所以如果你能分享你的代码来解决这个问题会更好。您可以共享仅针对此问题的代码。 我编辑了我的代码。如果我不从 superView 中删除微调器,我可以在 imagePickerController 消失后看到它。但不是在保存时。 (顺便说一句,感谢您一直以来的帮助!) 所以这意味着保存图像并没有花费太多时间。请记住,您正在使用动画解除 imagePickerController,因此它也需要一些时间,如果在这段时间内保存了图像,微调器也将被删除,您将看不到任何微调器。也许您可以尝试将这条线放在didFinishPickingMediaWithInfo 的顶部,而不用像picker.dismiss(animated: false, completion: nil) 这样的动画,然后再将微调器添加到视图中。这样您可能会看到微调器。 我也是这么想的,但是如果不是从相册中挑选照片,而是用相机拍照并保存,它会冻结一点,非常明显!也不可能在视图层次结构中看到它,因为如果我在将微调器添加为子视图后放置一个断点,当我单击按钮显示视图层次结构时,它无论如何都会关闭图像选择器!

以上是关于在 imagePicker 前面显示一个视图的主要内容,如果未能解决你的问题,请参考以下文章

ios编程,使用UINavigationcontroller里面的ImagePicker

如何在拍照之前使用 imagepicker 获取相机视图的大小

多个摄像头视图显示相同的摄像头馈送

在 iOS 7 的模态视图或表单中显示 UIImagePickerController?

是否可以在 UINavigationController 前面显示相机视图

如何在 tableViewCell 中运行 imagePicker