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!
source to share
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.
source to share