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
}
}
Related
I'm trying to use a UIImagePickerController to show a image picked from the Photo Library, but when I select the image, nothing happens.
All I'm doing is from Apple's Swift tutorial, so the code shouldn't be wrong, I guess. It doesn't work neither in simulator nor on a real device. I've tried all suggestions I found while googling. My code:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//MARK: Properties
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var mealNameLabel: UILabel!
#IBOutlet weak var photoImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
nameTextField.delegate = self
}
//MARK: Actions
#IBAction func selectImageFromPhotoLibrary(sender: UITapGestureRecognizer) {
// Hide the keyboard.
nameTextField.resignFirstResponder()
// UIImagePickerController is a view controller that lets a user pick media from their photo library.
let imagePickerController = UIImagePickerController()
// Only allow photos to be picked, not taken.
imagePickerController.sourceType = .photoLibrary
// Make sure ViewController is notified when the user picks an image.
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
// Dismiss the picker if the user canceled.
dismiss(animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
// Set photoImageView to display the selected image.
photoImageView.image = selectedImage
// Dismiss the picker.
dismiss(animated: true, completion: nil)
}
}
#IBAction func setDefaultLabelText(sender: UIButton) {
mealNameLabel.text = "Default Text"
}
//MARK: UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
mealNameLabel.text = textField.text
}
}
I can provide more information if necessary. Thanks in advance.
Your delegate method is in the button action scope.
You have to write UIImagePickerControllerDelegate method out of the selectImageFromPhotoLibrary action scope and write with the proper signature.
Just like that:
#IBAction func selectImageFromPhotoLibrary(sender: UITapGestureRecognizer) {
// Hide the keyboard.
nameTextField.resignFirstResponder()
// UIImagePickerController is a view controller that lets a user pick media from their photo library.
let imagePickerController = UIImagePickerController()
// Only allow photos to be picked, not taken.
imagePickerController.sourceType = .photoLibrary
// Make sure ViewController is notified when the user picks an image.
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
// Dismiss the picker if the user canceled.
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
// Set photoImageView to display the selected image.
photoImageView.image = selectedImage
// Dismiss the picker.
dismiss(animated: true, completion: nil)
}
I want to change the UIImagePickerController bottom bar buttons during
image editing mode in swift 3, Xcode 8.2.1.
Currently buttons are showing like as i mentioned in picture.
class MyController:UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imageV: RoundedImageView!
let imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
self.imagePicker.delegate = self
}
//MARK:- Action
#IBAction func libraryButtonPressed(_ sender: Any) {
self.imagePicker.allowsEditing = true
self.imagePicker.sourceType = .photoLibrary
self.present(self.imagePicker, animated: true, completion: nil)
}
#IBAction func cameraButtonPressed(_ sender: Any) {
self.imagePicker.allowsEditing = true
self.imagePicker.sourceType = .camera
self.present(self.imagePicker, animated: true, completion: nil)
}
// MARK: - UIImagePickerControllerDelegate Methods
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
self.imageV.contentMode = .scaleAspectFit
self.imageV.image = pickedImage
}
self.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.dismiss(animated: true, completion: nil)
}
}
Please suggest me..
Make sure you are not using Localization in your application, if you are using it, then properly configure all of your string files.
Have a look at this solution:
https://stackoverflow.com/a/42008789/2898708
I added PhotoLibrary.strings and in it I added following strings
"CANCEL" = "Cancel";
/* Title of button to set contact photo */
"SET_PHOTO_BUTTON" = "Set Photo";
"CHOOSE_PHOTO_BUTTON" = "Choose";
"USE_PHOTO_BUTTON" = "Use Photo";
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've 2 VC :
The first VC with 1 button when tapped >> 2 options post image form cam or library
Second VC chosen image form VC1 segued to the second VC
I tried to figured This the error without any success
fatal error: unexpectedly found nil while unwrapping an Optional value
pointed at
imageView.image=info[UIImagePickerControllerOriginalImage] as? UIImage
I uploaded the project in dropbox https://www.dropbox.com/s/w7blbnyac9qyxgw/segImage.zip?dl=0
VC1
class ViewController:UIViewController,UIAlertViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIPopoverControllerDelegate
{
#IBOutlet weak var btnClickMe: UIButton!
#IBOutlet weak var imageView: UIImageView!
var picker:UIImagePickerController?=UIImagePickerController()
var popover:UIPopoverController?=nil
override func viewDidLoad()
{
super.viewDidLoad()
picker!.delegate=self
// 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.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "" ) {
let destVC : second = segue.destinationViewController as! second
destVC.pics = imageView.image!
}
}
#IBAction func btnImagePickerClicked(sender: AnyObject)
{
let alert:UIAlertController=UIAlertController(title: "Choose Image", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
let cameraAction = UIAlertAction(title: "Camera", style: UIAlertActionStyle.Default)
{
UIAlertAction in
self.openCamera()
}
let gallaryAction = UIAlertAction(title: "Gallary", style: UIAlertActionStyle.Default)
{
UIAlertAction in
self.openGallary()
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel)
{
UIAlertAction in
}
// Add the actions
picker?.delegate = self
alert.addAction(cameraAction)
alert.addAction(gallaryAction)
alert.addAction(cancelAction)
// Present the controller
if UIDevice.currentDevice().userInterfaceIdiom == .Phone
{
self.presentViewController(alert, animated: true, completion: nil)
}
else
{
popover=UIPopoverController(contentViewController: alert)
popover!.presentPopoverFromRect(btnClickMe.frame, inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
}
func openCamera()
{
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
{
picker!.sourceType = UIImagePickerControllerSourceType.Camera
self .presentViewController(picker!, animated: true, completion: nil)
}
else
{
openGallary()
}
}
func openGallary()
{
picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
if UIDevice.currentDevice().userInterfaceIdiom == .Phone
{
self.presentViewController(picker!, animated: true, completion: nil)
}
else
{
popover=UIPopoverController(contentViewController: picker!)
popover!.presentPopoverFromRect(btnClickMe.frame, inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
picker .dismissViewControllerAnimated(true, completion: nil)
imageView.image=info[UIImagePickerControllerOriginalImage] as? UIImage
}
func imagePickerControllerDidCancel(picker: UIImagePickerController)
{
print("picker cancel.")
}
}
second VC
class second: UIViewController {
var pics = UIImage()
#IBOutlet var image: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
if let img = UIImage(named: "pics")
{
self.image.image = img
}
}
Your storyboard wiring is wrong.
The image should really be set on an instance of second rather than an instance of ViewController. Notice that the crash is happening in ViewController and not second
This code:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
picker .dismissViewControllerAnimated(true, completion: nil)
imageView.image=info[UIImagePickerControllerOriginalImage] as? UIImage
}
is attempting to set an imageView.image in ViewController. If you look at the Storyboard, there is no UIImageView in ViewController.
The way that you've defined imageView on ViewController is what makes this crash:
#IBOutlet weak var imageView: UIImageView!
With the ! there, you are saying, "This will never be nil." Well, that's obviously not the case because since this IBOutlet isn't wired to a UIImageView then it is nil. And thus, when you try to access it, BOOM!
To fix this:
Segue to second when the user picks an image
Set the selected image on second's image.imageView property
Other suggestion:
- Use consistency in naming, eg second vs SecondViewController
I am making an app in which there are two UIImageViews. In each image view the user needs to be able to input a different image. Here is the code I have so far.
var imagePicker = UIImagePickerController()
#IBAction func chooseImage1(sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.SavedPhotosAlbum){
println("Button capture")
imagePicker.delegate = self
imagePicker.sourceType = .SavedPhotosAlbum
imagePicker.allowsEditing = false
self.presentViewController(imagePicker, animated: true, completion: nil)
}
}
#IBAction func chooseImage2(sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.SavedPhotosAlbum){
println("Button capture")
imagePicker2.delegate = self
imagePicker2.sourceType = .SavedPhotosAlbum
imagePicker2.allowsEditing = false
self.presentViewController(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
chooseImage1.image = pickedImage
let pickedImage2 = info[UIImagePickerControllerOriginalImage] as? UIImage
chooseImage2.image = pickedImage2
dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
This ends up picking the same image for each different image view. I would like to be able to choose two individual photos, one for each view. Thank you for your help.
You only need one UIImagePickerController. You can keep a reference of the tapped view and when the user finish picking the image, you just need to cast the selected view as UIImageView and set its image property:
update: Xcode 11.5 • Swift 5.2 or later
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate ,UINavigationControllerDelegate {
#IBOutlet weak var imageView1: UIImageView!
#IBOutlet weak var imageView2: UIImageView!
var imagePicker = UIImagePickerController()
var selectedVew: UIView!
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
imagePicker.sourceType = .savedPhotosAlbum
imagePicker.allowsEditing = false
[imageView1,imageView2].forEach {
$0?.isUserInteractionEnabled = true
$0?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(chooseImage)))
}
}
#objc func chooseImage(_ gesture: UITapGestureRecognizer) {
if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) {
selectedVew = gesture.view
present(imagePicker, animated: true)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
(selectedVew as? UIImageView)?.image = info[.originalImage] as? UIImage
dismiss(animated: true)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true)
}
}