I'm trying to make the camera pop up on a button click, but my view is not persisting because I keep getting an error:
Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates.
I have an imageView rendered to place the picture when after it's shot, using the ImagePickerController function, but I'm guessing it's somehow not being pushed to the view.
Do you have any ideas?
Code that might be helpful is below:
- Basically, ViewController creates a UIView capturebutton, and when it is tapped, a Camera view controller is presented.
ViewController
class ViewController: UIViewController, UIScrollViewDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate{
let rect1 = CGRectMake(100, 60, 40, 60)
let captureButton2 = UIView(frame: rect1)
captureButton2.backgroundColor = UIColor.blueColor()
captureButton2.addGestureRecognizer(UITapGestureRecognizer(target: self, action: Selector("didTapImageView:")))
scrollView.addSubview(captureButton2)
func didTapImageView(tap: UITapGestureRecognizer){
let captureDetails = storyboard!.instantiateViewControllerWithIdentifier
("CameraVC")! as? CameraVC3
presentViewController(captureDetails!, animated: true, completion: nil)
}
CameraViewController
class CameraVC3: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIViewControllerTransitioningDelegate{
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera){
var imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera;
imagePicker.mediaTypes = [kUTTypeImage]
imagePicker.allowsEditing = false
self.presentViewController(imagePicker, animated: true, completion: nil)
}
}
var photoImageView2 = UIImageView(frame: CGRectMake(40, 120, 200, 200))
// handles output
func ImagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!){
photoImageView2.image = image
picker.dismissViewControllerAnimated(true, completion: nil)
}
Got it! I needed to add a line in my viewDidLoad() fn
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(photoImageView)
}
Related
I'm trying to load an instance of UIImagePickerController from a custom subview. For some reason it doesn't work and keeps giving me:
<UIImagePickerController: 0x7fde7282bc00> on <UIViewController: 0x7fde6f507f00> whose view is not in the window hierarchy!
Here's a skeleton of what my code looks like:
View Controller
let subview = SubView()
// Subview params...
subview.parent = self
self.view.addSubview(subview)
Subview
class SubView: UIView, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let imagePicker = UIImagePickerController()
var parent = UIViewController()
override func draw(_ rect: CGRect) {
imagePicker.delegate = self
let add = UIButton()
// add params...
add.addTarget(self, action: #selector(addImg(_:)), for: .touchUpInside)
self.addSubview(add)
}
func addImg(_ sender: UIButton) {
imagePicker.allowsEditing = false
imagePicker.sourceType = .photoLibrary
parent.present(imagePicker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
// Do stuff with image
}
}
}
Any ideas on how I can get this working?
You can get current rootController using UIApplication. This is my working code. It will find the rootController and check if it is type of UINavigationController or UIViewController
if let rootController = UIApplication.shared.keyWindow?.rootViewController {
if rootController is UINavigationController {
if let navigationController = rootController as? UINavigationController {
if let topViewController = navigationController.topViewController {
topViewController.present(alert, animated: true, completion: nil)
}
}
}
else {
// is a view controller
rootController.present(alert, animated: true, completion: nil)
}
}
I have 2 UIViewControllers:
ViewController 'A' named 'RERUN_SETUP' with an UIImageView and ViewController 'B' named 'SelectPhotos' with an imagePickerController.
There is an empty transparent UIButton over the UIImageView in ViewController 'A', which pops up ViewController 'B' and allows the user to select adding a picture from Camera or from Photos. ViewController 'A' is declared in ViewController 'B', but when I try to change the UIImageView on ViewController 'A' from ViewController 'B', the app crashes with an error
fatal error: unexpectedly found nil while unwrapping an Optional value.
Below is my code, any help will be greatly appreciated :)
ViewController 'A'
class RERUN_SETUP: UITableViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
//USER PICTURE
#IBOutlet weak var RERUNpictureIn: UIImageView?
//TRANSPARENT BUTTON OVER THE IMAGE VIEW
#IBAction func imageButton(sender: AnyObject) {
let popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("SelectPhotos")
popoverContent!.modalPresentationStyle = .Popover
popoverContent?.modalTransitionStyle = UIModalTransitionStyle.FlipHorizontal
var popover = popoverContent!.popoverPresentationController
if let popover = popoverContent!.popoverPresentationController {
let viewForSource = sender
popover.sourceView = self.view
popoverContent!.preferredContentSize = CGSizeMake(100,80)
popover.delegate = self
popover.permittedArrowDirections = .Any
}
self.presentViewController(popoverContent!, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
ViewController 'B'
import UIKit
class SelectPhotos: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var savedImage = NSUserDefaults.standardUserDefaults().objectForKey("image")
var imageToSave = UIImage()
var otherController:RERUN_SETUP = RERUN_SETUP()
#IBAction func camera(sender: UIButton) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.Camera
pickerController.allowsEditing = true
self.presentViewController(pickerController, animated: true, completion: nil)
}
#IBAction func photos(sender: AnyObject) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
pickerController.allowsEditing = true
self.presentViewController(pickerController, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion: nil)
self.imageToSave = image
otherController.RERUNpictureIn!.image = image
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
In View Controller B in your image picker delegate method save your image to nsuserdefault and in your viewconroller A get that image from nsuserdefault. and set the image.
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
let imageData = UIImagePNGRepresentation(image)
NSUserDefaults.standardUserDefaults().setObject(imageData!, forKey: "image")
NSUserDefaults.standardUserDefaults().synchronize()
}
and in your View Controller where you want to set the image
let imageData = NSUserDefaults.standardUserDefaults().objectForKey("image") as! NSData
imgView.image = UIImage(data: imageData)
The reason you are getting nil for RERUNpictureIn ImageView, is that it has not initalized yet for that empty object you have declare named otherController inside your SelectPhotos controller, Also that object will not helpful because the object you have create it not belongs to the object that is currently running with your application.
To send image to previous one you can use delegate/protocol for that.
First declare one protocol like this and implement with your RERUN_SETUP Controller
protocol ImageDelegate {
func getImage(image: UIImage)
}
Now implement it inside your
class RERUN_SETUP: UITableViewController, ImageDelegate, UIPopoverPresentationControllerDelegate {
//Your Code
//Implement method of ImageDelegate
func getImage(image: UIImage) {
self.RERUNpictureIn.image = image
}
}
Now add one object of ImageDelegate inside your SelectPhotos controller
import UIKit
class SelectPhotos: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var savedImage = NSUserDefaults.standardUserDefaults().objectForKey("image")
var imageToSave = UIImage()
var delegate: ImageDelegate?
#IBAction func camera(sender: UIButton) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.Camera
pickerController.allowsEditing = true
self.presentViewController(pickerController, animated: true, completion: nil)
}
#IBAction func photos(sender: AnyObject) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
pickerController.allowsEditing = true
self.presentViewController(pickerController, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.imageToSave = image
self.delegate.getImage(self.imageToSave)
self.dismissViewControllerAnimated(true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Note: Now inside RERUN_SETUP controller where you are creating object of SelectPhotos for presenting the view, just add one line before presenting the object.
objectOfSelectPhotosThatYouHvaeCreated.delegate = self
Typically, when I get this error, it has something to do with me having an extra "?" or "!" somewhere. Or that I'm missing one somewhere. Try messing around with those and see if it fixes your bug.
I am trying to make an image uploader on my ios app.
EDIT 7
This question is now more clearly asked here: Present Modal for Image Select Erases UI
END OF EDIT 7
The first thing I am trying to do is enable the user to select an image that they want for upload.
EDIT 6
I have simplified all the code to simply one button press. The Modal presentation deletes the previous page's UI. How I prevent this.
import UIKit
class AddImageToStandViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func loadImageButtonTapped(sender: UIButton) {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = .PhotoLibrary
self.presentViewController(imagePicker, animated: true, completion: nil)
}
}
I have found that the selection works just fine and does not destroy the UI if I push/segue from a different to this controller.
END OF EDIT 6
Below this is the other methods that I have tried before this
So far, this code enables a user to press a button and choose a photo from their photos. But, after they click the photo it just returns them to an empty View except the navbar at the bottom.
It seems my user is being returned, not to the view that they came from, but to a separate empty view. How do I return the user to the view that they came from?
import UIKit
class CreateStandViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet var image: UIImageView!
...
#IBAction func selectPicture(sender: AnyObject) {
let ImagePicker = UIImagePickerController()
ImagePicker.delegate = self
ImagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(ImagePicker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
image.image = info[UIImagePickerControllerOriginalImage] as? UIImage
self.dismissViewControllerAnimated(true, completion: nil)
}
...
let me know if there is any more information that I should give.
EDIT 1
this code has the same effect
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
image.image = info[UIImagePickerControllerOriginalImage] as? UIImage
picker.dismissViewControllerAnimated(true, completion: nil)
}
I have tried adding this line below but I get an error stating that CreateStandViewController.Type cannot be converted to the expected UIViewController.
self.presentViewController(CreateStandViewController, animated: true, completion: nil)
EDIT 2
This code below doesnt error but also changes nothing
let createStandController = CreateStandViewController()
self.presentViewController(createStandController, animated: true, completion: nil)
EDIT 3
I have literally copied all the code from here: http://www.codingexplorer.com/choosing-images-with-uiimagepickercontroller-in-swift/ and now have:
import UIKit
class CreateStandViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet var imageView: UIImageView!
let imagePicker = UIImagePickerController()
#IBAction func loadImageButtonTapped(sender: UIButton) {
imagePicker.allowsEditing = false
imagePicker.sourceType = .PhotoLibrary
presentViewController(imagePicker, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
// MARK: - UIImagePickerControllerDelegate Methods
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
imageView.contentMode = .ScaleAspectFit
imageView.image = pickedImage
}
dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
}
This has the same issue as before. When the image is selected I am sent back to a view that is white with the navbar at the bottom.
EDIT 4
I have run the same code in its own separate project as a stand alone view controller and it works. There is some code that I have in the background of my app that is killing the functionality of the code (maybe). I am guessing it may have something to do with the navbar?
EDIT 5
I removed the tab bar at the bottom by seguing to the image selecting view via a present Modally segue, but it had no effect.
Just replace your
self.dismissViewControllerAnimated(true, completion: nil)
with
picker.dismissViewControllerAnimated(true, completion: nil)
I think you will get the point after that
In my FirstVC I understand how to work with the UIImagePickerController, load the camera, take a photo, display it inside 1 imageView (still within the FirstVC) and then pass that image to an imageView inside the SecondVC via prepareForSegue to be shown over there.
What I need help with is having multiple imageViews inside FirstVC so that once a user takes the first picture it loads into the 1st imageView, then second picture the 2nd imageView, 3 pic to 3rd imageView, and 4th pic to 4th imageView. Afterwards an alert would appear that would say the user can't take any more pics and the user would press a nextSceneButton to be taken be taken to the SecondVC which would display the 4 chosen images that they just took.
I always used UIImagePickerController but I just got acquainted with AVFoundation. Should I use AVFoundation or UIImagePicker for this task?
Here is my UIImagePickerController code with only one imageView inside the FirstVC:
import UIKit
class FirstViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var nextSceneButton: UIButton!
//nextSceneButton is connected in StoryBoards and triggers the segue to the SecondVC
let imagePicker = UIImagePickerController()
var image: UIImage?
//MARK:- Custom Function
func noCamera(){
let alertVC = UIAlertController(title: "No Camera", message: "Sorry, this device has no camera", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "OK", style:.Default, handler: nil)
alertVC.addAction(okAction)
presentViewController(alertVC, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK:- Buttons
#IBAction func libraryButtonPressed(sender: UIButton) {
imagePicker.allowsEditing = false
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
presentViewController(imagePicker, animated: true, completion: nil)
}
#IBAction func photoButtonPressed(sender: UIButton) {
if (UIImagePickerController.availableCaptureModesForCameraDevice(UIImagePickerControllerCameraDevice.Rear) != nil){
imagePicker.allowsEditing = false
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureMode.Photo
imagePicker.cameraDevice = UIImagePickerControllerCameraDevice.Rear
presentViewController(imagePicker, animated: true, completion: nil)
}else{
noCamera()
}
}
//MARK:- ImagePickerController Delegates
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
self.image = chosenImage
imageView.image = self.image
dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
picker.dismissViewControllerAnimated(true, completion: nil)
}
//MARK:- Segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == “fromPhotoVcToSecondVC” {
let secondVC = segue.destinationViewController as! SecondViewController
secondVC.image = self.image
}
}
}//end class
You can add a count property and hold your images in an array :
var count = 0
var imageViews:[UIImageView]
Every time you take a photo and delegate gets called load the respective imageview :
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
self.imageViews[count].image = chosenImage
count +=1
dismissViewControllerAnimated(true, completion: nil)
}
Then if all photos are taken alert the user :
#IBAction func photoButtonPressed(sender: UIButton) {
if count < imageViews.count {
//present UiimagePicker
} else {
// alert no more pictures allowed
}
}
I have a new iOS app in Swift where I'm trying to show the camera as soon as the app is launched. In my view controller I have a single UIView object which I try to fill with the camera.
The code in my view controller calls UIImagePickerController in the viewDidLoad method but nothing happens.
Here is the code, any idea why nothing happens? Isn't the camera supposed to open on app launch with this code?
import UIKit
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let imagePicker = UIImagePickerController()
#IBOutlet weak var imageViewer: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.Front) {
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
presentViewController(imagePicker, animated: true, completion: nil)
} else {
println("no front camera available")
}
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
dismissViewControllerAnimated(true, completion: nil)
imageViewer.image = image
}
}
UPDATE: if I add a button to the storyboard, connect it to the code and put the code from viewDidLoad in it, the camera works when the button is clicked:
#IBAction func presentImagePicker(sender: AnyObject) {
if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.Front) {
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
presentViewController(imagePicker, animated: true, completion: nil)
}
}
I know that the camera works, but how to make it work without having to press a button?
Here is the solution for you.
Put your code in viewDidAppear method this way:
override func viewDidAppear(animated: Bool) {
if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.Front) {
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
presentViewController(imagePicker, animated: true, completion: nil)
}
}
This will load camera when your app start.
Trying to do it in viewDidLoad won't work because that is called after the view is first created, and the view isn't a subview of anything else at that point.
override func viewDidLoad() {
if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.Front) {
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
presentViewController(imagePicker, animated: true, completion: nil)
}
}