Swift: Segue directly to view controller from camera / UIImagePickerController

In my application, I want the user to be able to take a photo, submit an image and by clicking on the photo, a text box can be added so they can write over the image. This is exactly the same as the functionality of adding text to images in Snapchat.

As far as I understand, the only way to present the image after taking it and be able to edit it is to set:

       imagePicker.showsCameraControls = false

      

Create a custom overlay:

@IBAction func takePhoto(sender: UIButton) {
    imagePicker =  UIImagePickerController()
    imagePicker.delegate = self
    imagePicker.sourceType = .Camera
    imagePicker.showsCameraControls = false
    imagePicker.allowsEditing = true

    let overlayView = UIView(frame: CGRectMake(0, self.view.frame.width, self.view.frame.width, self.view.frame.height-self.view.frame.width))
    overlayView.backgroundColor = UIColor.blackColor()
    overlayView.alpha = 0.5
    println(overlayView)

    let snapButton = UIView(frame: CGRectMake(150, 160, 80, 80))
    snapButton.layer.cornerRadius = 40
    snapButton.userInteractionEnabled = true
    snapButton.backgroundColor = UIColor.purpleColor()
    overlayView.addSubview(snapButton)
    overlayView.bringSubviewToFront(snapButton)
    let recognizer = UITapGestureRecognizer(target: self, action:Selector("handleSnapTap:"))
    recognizer.delegate = self
    snapButton.addGestureRecognizer(recognizer)

    let cancelButton = UIView(frame: CGRectMake(40, 40, 44, 44))
    cancelButton.layer.cornerRadius = 22
    cancelButton.userInteractionEnabled = true
    cancelButton.backgroundColor = UIColor.redColor()
    overlayView.addSubview(cancelButton)
    overlayView.bringSubviewToFront(cancelButton)
    let cancelRecognizer = UITapGestureRecognizer(target: self, action:Selector("handleCancelTap:"))
    cancelRecognizer.delegate = self
    cancelButton.addGestureRecognizer(cancelRecognizer)


    let changeCameraButton = UIView(frame: CGRectMake(165, 40, 44, 44))
    changeCameraButton.layer.cornerRadius = 22
    changeCameraButton.userInteractionEnabled = true
    changeCameraButton.backgroundColor = UIColor.blueColor()
    overlayView.addSubview(changeCameraButton)
    overlayView.bringSubviewToFront(changeCameraButton)
    let changeCameraRecognizer = UITapGestureRecognizer(target: self, action:Selector("handleChangeCameraTap:"))
    changeCameraRecognizer.delegate = self
    changeCameraButton.addGestureRecognizer(changeCameraRecognizer)

    let flashButton = UIView(frame: CGRectMake(300, 40, 44, 44))
    flashButton.layer.cornerRadius = 22
    flashButton.userInteractionEnabled = true
    flashButton.backgroundColor = UIColor.yellowColor()
    overlayView.addSubview(flashButton)
    overlayView.bringSubviewToFront(flashButton)
    let flashRecognizer = UITapGestureRecognizer(target: self, action:Selector("handleFlashTap:"))
    flashRecognizer.delegate = self
    flashButton.addGestureRecognizer(flashRecognizer)

    imagePicker.cameraOverlayView = overlayView

    presentViewController(imagePicker, animated: true, completion: nil)
}

func handleSnapTap(recognizer: UITapGestureRecognizer) {
   println("Take picture")
    imagePicker.takePicture()
    self.performSegueWithIdentifier("cameraToImageViewSegue", sender: self)

}

func handleCancelTap(recognizer: UITapGestureRecognizer) {
    println("Cancel")
     self.imagePicker.dismissViewControllerAnimated(true, completion: nil)
}

func handleChangeCameraTap(recognizer: UITapGestureRecognizer) {

    if (hasChangedCamera == nil){
   imagePicker.cameraDevice = UIImagePickerControllerCameraDevice.Front
        hasChangedCamera = true
        return
    }

    if (hasChangedCamera == true){
        imagePicker.cameraDevice = UIImagePickerControllerCameraDevice.Rear
        hasChangedCamera = false
        return
    }

    if (hasChangedCamera! == false){
        imagePicker.cameraDevice = UIImagePickerControllerCameraDevice.Front
        hasChangedCamera = true
        return

    }
}

func handleFlashTap(recognizer: UITapGestureRecognizer) {

    if (hasTurnedOnFlash == nil){
        imagePicker.cameraFlashMode = UIImagePickerControllerCameraFlashMode.On
        hasTurnedOnFlash = true
        return
    }

    if (hasTurnedOnFlash == true){
        imagePicker.cameraFlashMode = UIImagePickerControllerCameraFlashMode.Off
        hasTurnedOnFlash = false
        return
    }

    if (hasTurnedOnFlash == false){
        imagePicker.cameraFlashMode = UIImagePickerControllerCameraFlashMode.On
        hasTurnedOnFlash = true
        return
    }

}

      

Finally, let's introduce a new view controller in which the selected image is placed in a UIView and edit it from there. My problem is how to navigate directly from the UIImagePickerController to the new view controller. I've tried the following:

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {

    self.imagePicker.dismissViewControllerAnimated(false, completion: nil)
   let vc = ModifyCameraImageViewController() //change this to your class name
    self.presentViewController(vc, animated: false, completion: nil)

}

      

First, it just results in a black screen, but I'm sure there is a fairly simple way around it. My main problem is that the view controller from which the UIImagePickerController was presented briefly appears on the screen before the next view controller appears. It clearly doesn't look good. I have also tried removing the rejectViewController function and also placing the presentViewController function above the showView controller function. Both of these attempts gave me an error message:

Warning: Attempt to present <xxx.ModifyCameraImageViewController: 0x145e3eb70> on <xxx.ViewController: 0x145d20a60> whose view is not in the window hierarchy!

      

Trying to use performSegueWithIdentifier with segue binding to base view and next view controller gives same error warning.

I found the following similar question, but I am not completely familiar with Objective C, so I am struggling to understand it: Click the viewController from the UIImagePickerController camera view

So, can anyone help on how to expose the view controller directly from the UIImagePickerController?

Also, keep in mind that I am doing this to be able to create a text overlay on a newly selected image (for example on Snapchat), so if anyone has a more elegant solution feel free to post this!

Thank!

+3


source to share


2 answers


Ok, found a simple solution to my problem. Instead of presenting an imagePickerController from the main view controller when the takePicture button is clicked and navigating to another view controller directly from there, use the takePicture button to navigate to another view controller and present the imagePickerController from the second view controller's viewDidLoad. The second view manager will be presented after rejecting the imagePickerController function. However, this requires the main view controller to look the same as the camera controls, and some to play with animations to make it look natural.



+5


source


let pickerController: Void = picker.dismissViewControllerAnimated(true) { _ in
        UIImageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
        self.performSegueWithIdentifier("segueIdentifier", sender: nil)
        //Do what you want when picker is dismissed
    }

      



0


source







All Articles