How to change image on clicking existing image in iOS? - ios

I have a button within tableViewcell with Image contained in it. I want to get option to change the image on tapping the previous image(which is a button),like opening gallery or camera.I am using following code to implement this:
In tableView cell:
protocol Profile2 : class{
func OnClick_2(index : Int)
}
class TableViewCell: UITableViewCell {
weak var celldelegate : Profile2?
var index : IndexPath?
}
In View Controller
#IBAction func changeProfileImage(_ sender: Any) {
let action_sheet = UIAlertController(title: "Click to choose photo", message: nil, preferredStyle: .actionSheet)
action_sheet.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { (action) in
self.ShowAlbum()
}))
action_sheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
}
//Show album method
func ShowAlbum()
{
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
imagePicker.allowsEditing = true
}
//In cell for row method:
cell.celldelegate = self
cell.index = indexPath
cell.profilePicture.isUserInteractionEnabled = true
//imagepicker method
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!){
self.dismiss(animated: true, completion: { () -> Void in
})
let cell = tableView.dequeueReusableCell(withIdentifier: "profilePictureCell") as! TableViewCell
cell.profilePicture.imageView?.image = image
}
on tapping the button actionsheet is opened for uploading image from gallery but on selecting image and uploading it is not getting set into the button.
Please suggest me how to solve it or do it in alternative way.

Related

Tap gesture in a view controller causing delay in opening of the view controller when a button in other view controller is pressed

I have implemented a tap gesture on UIStackView in one ViewController which is embedded in a Tab Bar. When I click button on tab bar to open it, it causes a delay of few seconds and then opens the View Controller. After searching for a while on internet I found out tap gestures might cause this and apparently when I remove this tap gesture, it works smoothly. The solution they suggested was just remove tap gesture as in most cases they did not want it and it was accidentally there however I do want tap gestures so I cannot remove it. This is how I have added a simple tap gesture in viewDidLoad():
let tapAddImage = UITapGestureRecognizer(target: self, action: #selector(self.addImage(_:)))
tapAddImage.cancelsTouchesInView = false
svAddImage.addGestureRecognizer(tapAddImage)
This function opens image picker.
Also I just noticed the same issue is caused in other ViewControllers too where I have implemented imagePicker which is opened by tapping something using Tap Gesture. Here is my image picker delegate functions:
#objc func addImage(_ sender: UITapGestureRecognizer) {
openCameraOrGallery()
}
func openCameraOrGallery() {
let alert = UIAlertController(title: BaseUrl.shared.projectName, message: "Select Option", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default , handler:{ (UIAlertAction)in
self.present(self.imagePicker!, animated: true, completion: {
self.imagePicker?.sourceType = .camera
self.imagePicker?.delegate = self
})
}))
alert.addAction(UIAlertAction(title: "Gallery", style: .default , handler:{ (UIAlertAction)in
self.present(self.imagePicker!, animated: true, completion: {
self.imagePicker?.sourceType = .photoLibrary
self.imagePicker?.delegate = self
})
}))
alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler:{ (UIAlertAction)in
print("User click Dismiss button")
}))
self.present(alert, animated: true, completion: {
print("completion block")
})
}
//MARK: UIImagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let tempImage:UIImage = info [.originalImage] as? UIImage else {return}
self.ivSelectedPostImage.image = tempImage
let imageData:NSData = tempImage.jpegData(compressionQuality: 0.2)! as NSData
postBase64 = imageData.base64EncodedString(options: .lineLength64Characters)
self.svAddPostContentButtons.isHidden = true
self.viewSelectedPostImage.isHidden = false
self.dismiss(animated: true, completion: nil)
}
func cancelButtonDidPress(_ imagePicker: UIImagePickerController) {
imagePicker.dismiss(animated: true, completion: nil)
}
I have just copy pasted this code from my other project. There is no issue in any other project with ImagePicker Delegates or tap gestures. Any idea what might be causing delay only in these pages where I open camera or gallery by using tap gestures? This is only happening to those ViewControllers where im clicking a button to open these ViewControllers having tap gestures.
Please try to initialise the tap gesture in ViewDidAppear.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let tapAddImage = UITapGestureRecognizer(target: self, action: #selector(self.addImage(_:)))
tapAddImage.cancelsTouchesInView = false
svAddImage.addGestureRecognizer(tapAddImage)
}

iOS camera shows briefly then disappears after being presented from table view cell

One of my table cells is set up with a delegate to call a UIAlert action sheet which allows user to select a photo from library, or take photo with the camera. The alert shows and selection from library is working fine but if camera is selected the camera view will show for a couple of seconds and then animates itself downwards off screen, disappearing. I am testing with a real device can anyone explain why only the camera view is not showing correctly?
Table cell is set up with a delegate to show the UIAlert and the cell delegate is set to self(UserProfileViewController class) in cellForRowAt:
class UserProfileProfilePictureTableViewCell: UITableViewCell {
...
protocol UserProfilePictureDelegate {
func changeProfileImage()
}
#IBAction func addProfileImageTapped(_ sender: Any) {
self.delegate?.changeProfileImage()
}
}
.
class UserProfileViewController: BaseViewController, UITableViewDataSource, UITableViewDelegate, UserProfileHeaderDelegate, UserProfilePictureDelegate, UserProfileSignatureDelegate, DrawSignatureDelegate, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
func changeProfileImage() {
profileImagePicker = UIImagePickerController()
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Upload from Gallery", style: .default , handler:{ (UIAlertAction)in
if let imagePicker = self.profileImagePicker {
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
}))
alert.addAction(UIAlertAction(title: "Upload from Camera", style: .default , handler:{ (UIAlertAction)in
if let imagePicker = self.profileImagePicker {
imagePicker.sourceType = .camera
imagePicker.allowsEditing = true
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
}))
alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler:{ (UIAlertAction)in
}))
if let popoverController = alert.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
}
DispatchQueue.main.async {
self.present(alert, animated: true, completion: nil)
}
}
}

iOS Camera with multiple imageView outputs

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
}
}

How to pass a selected image from ImagePickerController to second view controller?

I've tried exhaustively to find the answer to this problem. In the app that I am creating the user will click addImage button and then select an image from the photo library (or camera) from ImagePickerController and then that selected image gets passed to an image view on a second view controller.
I know how to do this when the image view is on the same view as the addImage button but can't figure out how to properly use a segue to pass the image to the second view. Hopefully, someone can help me sort this out.
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{
var newImage = UIImage(named: "")
#IBOutlet var imageView: UIImageView!
var imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func addImage(sender: UIButton) {
var alert = UIAlertController(title: "Please Get An Image", message: "Choose from below", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Camera", style: .Default, handler: {(action) -> Void in
self.imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Photo Library", style: .Default, handler: {(action) -> Void in
self.imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: {(action) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
newImage = image
//not sure about this next line here...
performSegueWithIdentifier("VC2", sender: self)
self.dismissViewControllerAnimated(true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var secondViewController: VC2 = segue.destinationViewController as! VC2
secondViewController.imageView.image = newImage
}
}// end of app
you should not pass the UIImage by using the UIImageView object because this is not a Good idea to pass the image like this, Instead you can create UIImage object in SecondViewController simple pass the UIImage object to that and in SecondVC use this image object like this
override func viewDidLoad() {
super.viewDidLoad()
if imageView != nil {
imageView.image = newImage
}
}
OK susan, so when you click "Use Photo" in the preview part of the camera, that's where you want to implement to segue to the second VC.
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
newImage = image
dismissViewControllerAnimated(true, completion: { () -> Void in
//Will call segue name
self.performSegueWithIdentifier("Your_Segue_name", sender: self)
})
}
EDIT: The above code will segue after you've confirmed that you want to use the image.
In your second VC, have a holder to hold then sent that holder image to your UIImageView. In your 1st VC, sent the image to transfer to the holder image.
Your SecondVC:
#IBOutlet var imgView: UIImageView!
var holderImage: UIImage?
In your viewDidLoad()
imgView.image = holderImage.image
Make sure the segue has its identifier set as "VC2". Also, instead of setting
secondViewController.imageView.image = newImage
expose a property on your secondViewController that takes the image. Set the property with the image in prepareForSegue.
secondViewController.image = newImage
Then, in viewDidLoad on secondViewController set its imageView with the value from the property.
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = image
}
In your code the ImageView on the second controller doesn't exist yet because of the view life cycle.
You can also set a breakpoint in prepareForSegue to make sure it's being called properly and the second controller is being set properly.

Passing Selected Image from UIImagePicker to a Second View Controller

I've looked all over for a solution but haven't been able to find one. I want to be able to select an Image from the UIImagePicker and have that image go to an ImageView in a Second View Controller. I have a button that triggers an AlertView with options to get photos from camera or library. It works fine if I want the selected image to go to an image view on the first view but I can't get it to work to have it go to a second view. Any suggestions would be greatfully appreciated. `
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{
var newImage = UIImage(named: "")
#IBAction func libraryBtn(sender: AnyObject) {
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
presentViewController(imagePicker, animated: true, completion: nil)
}
#IBOutlet var imageView: UIImageView!
var imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = UIImage(named: "beach.jpg" )
imagePicker.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func addButton(sender: UIButton) {
var alert = UIAlertController(title: "Please Get An Image", message: "Choose from below", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Camera", style: .Default, handler: {(action) -> Void in
self.imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Photo Library", style: .Default, handler: {(action) -> Void in
self.imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: {(action) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
newImage = image
performSegueWithIdentifier("VC2", sender: self)
self.dismissViewControllerAnimated(true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var secondViewController: VC2 = segue.destinationViewController as! VC2
secondViewController.imageView.image = newImage
}
}
I dont know Swift but I do know ObjC, so I will try to explain:
Class 2 .h :
#property (nonatomic, strong) UIImageView *myImageViewer;
Class 1 .m :
mySecondViewController.myImageViewer = [UIImageView new];
[mySecondViewController.myImageViewer setImage: newImage];
First you need to make the ImageView global to be able to access from other controllers. Then after you picked the newImage, you initialize memory to myImageViewer and give it the newImage you just picked, then load the viewController.
Hope this is what you needed to hear?

Resources