I have minor problem that whenever I delete the Outlet (imageChosen) shown in the picture below (with the yellow warning), the app crashes when the image supposed to be passed
here how i defined it
var imageChosen: UIImageView!
this is how i saved the image chosen from the gallery to the imageChosen
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
var chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
imageChosen.contentMode = .ScaleAspectFit
imageChosen.image = chosenImage
dismissViewControllerAnimated(true, completion: nil)
self.performSegueWithIdentifier("next", sender: self)
}
this where I pass the image to the next activity
override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!) {
if segue.identifier == "next" {
var pass:postView = segue.destinationViewController as! postView
pass.currentImage = imageChosen.image
}
}
when I delete the outlet in the picture, the app crashes because the image is nil, even though the code seems to be okay,
can anyone please help me
The reason why you keep getting the error is because you are assign image without allocation of your imageChosen.
The Solution
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
// Add this line
imageChosen = UIImageView()
}
After you have declare that imageChosen = UIImageView(), it will solve your problem
Hope that helps!
You need to delete the outlet from the ViewController(swift file) as well, where you see the outlets in the pic you post click in the (x) to delete the outlet from imageChosen as it does not exist anymore (you can see the warning from Code in form of a yellow triangle).
You should also change your code to:
var imageChosen: UIImageView?
this is how i saved the image chosen from the gallery to the imageChosen
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
if let image = info[UIImagePickerControllerOriginalImage] as UIImage{
imageChosen.contentMode = .ScaleAspectFit
imageChosen.image = image
}
else
{
//something went wrong
}
dismissViewControllerAnimated(true, completion: nil)
self.performSegueWithIdentifier("next", sender: self)
}
this where I pass the image to the next activity
override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!) {
if segue.identifier == "next" {
if let pass = segue.destinationViewController as postView
{
if let image = imageChosen.image{
pass.currentImage = imageChosen.image
}
}
}
}
I did it very verbose to make it easier to understand
Related
This question already has answers here:
Picking two different images in the same view controller using imagePickerController in Swift
(1 answer)
Select Multiple Images (UIImagePickerController or Photos.app Share UI)
(8 answers)
Closed 3 years ago.
I want to pick images from phone library when I tap on two different UIImageViews and after selection, display them on two different UIImageView's,
but I when run the following code, the same image displays at two different UIImageViews, How can I fix it?
'''
extension SettingProfileViewController:UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
profilePhoto.image = image
print("profile")
}
if let wallImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
wallpaperPhoto.image = wallImage
print("wallpaper")
}
dismiss(animated: true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(SettingProfileViewController.handleSelectProfilePhotoView))
profilePhoto.addGestureRecognizer(tapGesture)
profilePhoto.isUserInteractionEnabled = true
let wallTapGesture = UITapGestureRecognizer(target: self, action: #selector(SettingProfileViewController.handleSelectWallpaperImageView))
wallpaperPhoto.addGestureRecognizer(wallTapGesture)
wallpaperPhoto.isUserInteractionEnabled = true
}
#objc func handleSelectProfilePhotoView(){
let pickerController = UIImagePickerController() //открывает галерею
pickerController.delegate = self
present(pickerController, animated: true, completion: nil)
}
#objc func handleSelectWallpaperImageView(){
let pickerCont = UIImagePickerController()
pickerCont.delegate = self
present(pickerCont, animated: true, completion: nil)
}
'''
What you observe is that when the user taps on any of the image views (wallpaperPhoto or profilePhoto), the UIImagePickerController always uses self as its delegate. Then, when the user picks an image, the delegate cannot distinguish any more which image view originally was tapped.
You could simply add a weak optional variable indicating the "active" tapped image view, and then set only it's image. Also, you can reduce the tap handler to a single function with a sender argument, which is the image view the user tapped on, and set the activeImageViewto this.
extension SettingProfileViewController:UIImagePickerControllerDelegate, UINavigationControllerDelegate {
weak var activeImageView:UIImageView? = nil
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
activeImageView.image = image
}
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(SettingProfileViewController.handleSelect(_:))
profilePhoto.addGestureRecognizer(tapGesture)
profilePhoto.isUserInteractionEnabled = true
let wallTapGesture = UITapGestureRecognizer(target: self, action: #selector(SettingProfileViewController.handleSelect(_:)))
wallpaperPhoto.addGestureRecognizer(wallTapGesture)
wallpaperPhoto.isUserInteractionEnabled = true
}
#objc func handleSelect(sender:UIGestureRecognizer) {
guard let sendingImageView = sender.view as? UIImageView else {
print("Ooops, received this gesture not from an ImageView")
return
}
activeImageView = sendingImageView
let pickerController = UIImagePickerController() //открывает галерею
pickerController.delegate = self
present(pickerController, animated: true, completion: nil)
}
// ...
I am trying to make an app the takes pictures every so often with this code
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var cameraIsOn = false
let imagePicker = UIImagePickerController()
var timeInterval = 15
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
imagePicker.allowsEditing = false
imagePicker.sourceType = .camera
}
#IBAction func PlayButton(_ sender: UIBarButtonItem) {
present(imagePicker, animated: true) {
self.cameraIsOn = true
self.imagePicker.takePicture()
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
imageView.image = image
}
imagePicker.dismiss(animated: true) {
self.present(self.imagePicker, animated: true) {
self.cameraIsOn = true
if self.cameraIsOn {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(self.timeInterval * 60), execute: {
self.imagePicker.takePicture()
})
}
}
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
cameraIsOn = false
}
}
After a picture is taken. You are shown a "retake or use photo screen".
I am trying to press the "use photo" button programmatically so that I can complete the loop until someone presses cancel.
Not sure of what button(use photo) action you are looking for! but to call/press a UIButton programmatically. Try this
yourButton.sendActions(for: .touchUpInside)
It would be better if you make your question more detailed. What is your scenario? What exactly you are tying to achieve?
I have a UIViewController that allows the user to select a photo or a video via UIImagePickerController. Once they select one of them the image is being assigned to a property called var selectedImage (if they select a video, there's a method that generates a thumbnail for that video). It works as expected.
The problem is that I want to handle the state of 2 UIBarButtonItems. I want to disable them when selectedImage is nil and set the isEnabled once there's an image.
Pretty straight forward, right? Well, the problem is that initially it loads the UIViewController, the buttons are disabled and visible, then I select a photo from the gallery, didFinishPickingMediaWithInfo is called and in there, I also call handlePost() method that should take care of the state (enabled/disabled) of the buttons. Well, for some reason, even though there's an image in selectedImage, the buttons are not being displayed (practically invisible, but as far as I know, there's no isHidden for UIBarButtonItem.
They are still active, if i tap on them (despite not seeing them) they do their job. Now, the problem is why are not they visible? I can guarantee Colors.tint has a value (I use this class throughout the app, it works) and the selectedImage has a value (I've put a break point and it calls the handlePost() method, goes through the first if statement where that property has a value. Yet, I don't see the buttons being displayed. The question is why?
#IBOutlet weak var clearButton: UIBarButtonItem!
#IBOutlet weak var filterButton: UIBarButtonItem!
var selectedImage: UIImage?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
handlePost()
}
func handlePost() {
if selectedImage != nil {
clearButton.isEnabled = true
clearButton.tintColor = Colors.tint
filterButton.isEnabled = true
filterButton.tintColor = Colors.tint
shareButton.isEnabled = true
shareButton.backgroundColor = Colors.tint
shareButton.setTitleColor(.white, for: .normal)
}
else {
clearButton.isEnabled = false
clearButton.tintColor = .darkGray
filterButton.isEnabled = false
filterButton.tintColor = .darkGray
shareButton.isEnabled = false
shareButton.backgroundColor = .darkGray
shareButton.setTitleColor(.lightGray, for: .normal)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let videoUrl = info[UIImagePickerController.InfoKey.mediaURL] as? URL {
if let thumbnail = self.generateThumbnailForImage(videoUrl) {
self.videoUrl = videoUrl
self.photoImageView.image = thumbnail
self.selectedImage = thumbnail
handlePost()
}
}
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
selectedImage = image
photoImageView.image = image
handlePost()
}
dismiss(animated: true, completion: nil)
}
As I mentioned in the comments, I'm not sure what's the issue because there's no problem for this to happen. But the simply solution was to remove the UIBarButtonItems and just replace them with UIButtons instead. This did the trick and now they're behaving the way they should.
My UIImageView is always blank. When the image view is loaded I have it print the image and image view out. This is the output from the print in first section of code: UIImage: 0x170898010>, {4032, 3024}
UIImageView: 0x14bb077e0; frame = (0 64; 375 554); This is the output from the print in second section of code: autoresize = RM+BM; userInteractionEnabled = NO; layer = CALayer: 0x170a31240 It seems to be storing the image but it does not appear.
Here is where the image, which is saved correctly to CloudKit is downloaded and converted:
if let asset = record["Picture"] as? CKAsset,
let data = NSData(contentsOf: asset.fileURL),
let image1 = UIImage(data: data as Data)
{
let eventPageViewController:EventPageViewController = self.storyboard?.instantiateViewController(withIdentifier: "EventPage") as! EventPageViewController
eventPageViewController.toPass = image1
print(image1)
}
Here is the code for the ViewController that displays the UIImageView:
class EventPageViewController: UIViewController {
#IBOutlet weak var eventPic: UIImageView!
var toPass: UIImage!
override func viewDidLoad() {
super.viewDidLoad()
eventPic.image = toPass
print(eventPic)
}
here is where the eventPageViewController appears:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let eventPageViewController:EventPageViewController = storyboard?.instantiateViewController(withIdentifier: "EventPage") as! EventPageViewController
self.present(eventPageViewController, animated: true, completion: nil)
}
From Apple docs about image property:
This property is set to the image you specified at initialization time. If you did not use the init(image:) or init(image:highlightedImage:) method to initialize your image view, the initial value of this property is nil.
https://developer.apple.com/reference/uikit/uiimageview/1621069-image
The OP isn't using segues, but I was asked if this would solve things. Here's my description and code that works using a segue.
Baseline:
My app has two view controllers (select and edit) with a segue between them (ShowEditView). That is all I've defined in IB. Everything else is in code.
There is one difference that appears to not be at issue - I use a UIImagePickerController to get the image where the OP pulls it from the assets. This doesn't appear to be at issue because the source VC has the image. So picking it up from here (two VCs with a segue defined in IB, the image in a UIImage instance) here's how I might code things based on the OP's code.
In the source VC:
func imageAttained() {
// here's where you move the image into image1
// this is the segue - make sure you've named it in IB
self.performSegue(withIdentifier: "ShowEventView", sender: self)
}
// this is an override in the source VC and passes the image
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowEventView" {
if let vc = segue.destination as? EventPageViewController {
vc.toPass = image1
}
}
}
And in the destination VC (EventPageViewController):
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
eventPic.image = toPass
}
Since iOS 9 and Xcode 7 I am no longer able to implemet a UIImagePickerController on an iPad (both device and simulator). The code below works on the iPad but only prior to iOS 9. When using iOS 9+ the presented image (after the UIImagePickerController is dismissed) is an incorrect version of the selected image. Without re-sizing or cropping the final image is only the top right corner of the original image ?? Plus another problem - If imagePicker.allowsEditing = false, you are unable to select images from the PhotoLibrary ??
#IBAction func photoButton(sender: AnyObject) {
imagePicker.allowsEditing = true
imagePicker.sourceType = .PhotoLibrary
self.presentViewController(imagePicker, animated: false, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let pickedImage = info[UIImagePickerControllerEditedImage] as? UIImage {
self.imageView.image = pickedImage
dismissViewControllerAnimated(true, completion: { () -> Void in
})
}
Heres an example of a selected image presented in a UIImagePickerController. (notice how the selected image is presented very small and not full size/width of screen as before)
After selecting the use button within the UIImagePickerController the final image is only the top right of the original image. What am I doing wrong or is UIImagePickerController broken on iOS 9 ?
This is a bug from Apple:
http://openradar.appspot.com/radar?id=5032957332946944
Current lousy workaround:
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
imagePicker.allowsEditing = false
} else {
imagePicker.allowsEditing = true
}
Swift 3.0:
if UIDevice.current.userInterfaceIdiom == .pad {
}
Refer the below coding
#IBAction func photoButton(sender: AnyObject)
{
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
{
picker!.sourceType = UIImagePickerControllerSourceType.Camera
self .presentViewController(picker!, animated: true, completion: nil)
}
else
{
let alertWarning = UIAlertView(title:"Warning", message: "You don't have camera", delegate:nil, cancelButtonTitle:"OK", otherButtonTitles:"")
alertWarning.show()
}
}
func openGallary()
{
picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(picker!, animated: true, completion: nil)
}
//PickerView Delegate Methods
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject])
{
picker .dismissViewControllerAnimated(true, completion: nil)
imageView.image=info[UIImagePickerControllerOriginalImage] as? UIImage
}
func imagePickerControllerDidCancel(picker: UIImagePickerController)
{
println("picker cancel.")
}
You need to make sure you have the correct frame for your imageview and the contentmode for your imageview should be aspectfit and the image returned by the picker is of type [UIImagePickerControllerOriginalImage]
[imageView setFrame:imageViewRect];
[imageView setContentMode:UIViewContentModeScaleAspectFit];
Swift:
imageView.setFrame(imageViewRect)
imageView.setContentMode(UIViewContentModeScaleAspectFit)
and coming to the allowsEditing property, It is not related to photo selection.
It is a Boolean value indicating whether the user is allowed to edit a
selected still image or movie.
If you want to select photos from camera library, then you need to modify the source type to
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
Update:
LEts say you have selected one image and display it on the image view. I assume you have one imageview on the view, and the imageview frame is equal to the view frame. If the IB is of freeform , I assume the size 600x600 for the imageview frame in the IB.
if you simply do:
_startImageView.image=_img;
The result will be:
Now let's make some changes to the image to be displayed in the imageview:
CGRect scaledRect = AVMakeRectWithAspectRatioInsideRect(_img.size, CGRectMake(0, 0, self.startImageView.frame.size.width, self.startImageView.frame.size.height));
UIGraphicsBeginImageContext(CGSizeMake(_startImageView.frame.size.width,_startImageView.frame.size.height));
[_img drawInRect:scaledRect];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
_startImageView.image=scaledImage;
and now the image will be:
The original image choosen is of size 640x426, when not scaled.
The original image choosen is of size 1536x1286 when scaled to max(with two finger zoom action).
As you can see, still there is no huge change in the image, it is because the image is already cropped/scaled by the time your imageview recieved the image!!!
So even though you try to do:
[_img drawInRect:_startImageView.frame];
The image will not be drawn as per our need, as the image is already scaled right at them moment as the image given by the picker is the edited image.
Solution:
To fix this, you need to select the original image from picker in didFinishPickingMediaWithInfo: method
info[UIImagePickerControllerOriginalImage];
which gives you the image:
This code is relatively similar to #pkc456, just a little shorter.
This works perfectly for me:
import UIKit
class PostImageViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
#IBOutlet var imageToPost: UIImageView!
#IBAction func chooseImage(sender: AnyObject) {
var image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
image.allowsEditing = false //or true additional setup required.
self.presentViewController(image, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion:nil)
}
Does this work?
I am working on xcode 7.1(Swift) and found your code appropriate. I also wrote the below code on my project and it is working successfully.
func showPicker(){
let type = UIImagePickerControllerSourceType.PhotoLibrary
if(UIImagePickerController.isSourceTypeAvailable(type)){
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
pickerController.allowsEditing = false
self.presentViewController(pickerController, animated: true, completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!) {
let imageView = self.view.viewWithTag(20) as! UIImageView
let selectedImage : UIImage = image
imageView.image=selectedImage
self.dismissViewControllerAnimated(true, completion: nil)
}
The only difference in your code and my code is about visibility of ImagePickerController instance. For your reference, I upload my code at:-
https://www.dropbox.com/s/pe0yikxsab8u848/ImagePicker-Swift.zip?dl=0
My idea is just look at my code once, may be you will get an idea about which section of your code malfunctioning.
It seems like you are using IB and auto layout but have set a right constraint. Try to add some constraint in your storyboard.
for me I was solved, showing mode as popover
#IBAction func photoButton(sender: AnyObject) {
imagePicker.allowsEditing = true
imagePicker.sourceType = .PhotoLibrary
let controller = self.imagePicker
controller.modalPresentationStyle = UIModalPresentationStyle.Popover
controller.modalTransitionStyle = UIModalTransitionStyle.CoverVertical
let popover = controller.popoverPresentationController
popover?.sourceView = self
controller.preferredContentSize = CGSize(
width: self.frame.width * 0.6,
height: self.frame.height * 0.6
)
popover?.sourceRect = CGRectMake(
CGRectGetMidX(self.bounds),
CGRectGetMidY(self.bounds),
0,
0
)
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}