1

I am asking if it is possible to set the image of a UIImageView using a gestureRecognizer, or is it necessary to overlay a button on top of the UIImageView.

I have an outlet collection of UIImageViews, called imageViews. There are four of these, and their tags have been set from 1 to 4. In my viewDidLoad, to add the gesture recognizer to each of the image views in the collection, i have used:

override func viewDidLoad() {
    super.viewDidLoad()

    for i in (0..<imageViews.count) {

        let imageViewTapped = UITapGestureRecognizer(target: self, action: #selector(selectImage(tap:)))
        imageViewTapped.numberOfTapsRequired = 1
        imageViews[i].addGestureRecognizer(imageViewTapped)

    }

}

Next, I created my gestureRecognizer as a function in the viewController class. This is where the image picker controller is created and where the image view that was tapped is identified:

func selectImage(tap: UITapGestureRecognizer) {

    var imagePicker = UIImagePickerController()
    imagePicker.delegate = self
    imagePicker.sourceType = .photoLibrary
    imagePicker.allowsEditing = false
    imagePicker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
    self.present(imagePicker, animated: true, completion: nil)

    guard let viewTappedTag = tap.view?.tag else {return}
    self.selectedImageView = imageViews[viewTappedTag - 1] 

}

selectedImageView is a variable in the viewController class with a type of UIImageView. My thinking was that this variable could hold the UIImageView that was tapped, which is identified by the gestureRecognizer, as shown above. This could then be passed to the delegate later on.

Next, I created the delegates, the didFinishPickingMediaWithInfo and didCancel, though I will only show the former for brevity. Both were created inside the viewController class:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

    var chosenImage = UIImage()
    chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
    self.selectedImageView.image = chosenImage

    dismiss(animated: true, completion: nil)

}

Unfortunatley, the image of the image view that was tapped is not updated to the one that was chosen from the library. What is the correct way to do this? And I feel as though I am bloating my viewController with all of this code, can this be moved to a seperate class? Am i wrong in doing it like this, and instead one should just overlay a button?

EDIT

The best I could come up with so far is a switch statement in my imagePickerController, where imageViewOne, imageViewTwo etc are outlets for each UIImageView:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

    var chosenImage = UIImage()
    chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage

    switch self.viewTappedTag {
    case 1:
        imageViewOne.image = chosenImage
    case 2:
        imageViewTwo.image = chosenImage
    case 3:
        imageViewThree.image = chosenImage
    case 4:
        imageViewFour.image = chosenImage
    default:
        imageViewOne.image = chosenImage

    }

    dismiss(animated: true, completion: nil)

}

where viewTappedTag is a viewController class variable, the value of which is defined by the tag of the view that was tapped and is set in the gestureRecognizer. Can anyone improve on this?

pho_pho
  • 672
  • 11
  • 30
  • If i'm not wrong your aim is to create an interface which have 5 image views out of which 4 have a gesture recognizer and after you tap on one..it should be the image that will get changed when a new image is added from image picker controller to selectedImageView? – Mukul More Apr 13 '17 at 13:14
  • Hi @MukulMore, almost, I have 4 image views, not five, but the rest of your statement is correct. I have set the tags of the image views from 1 to 4 as the default tag value for an object is 0. – pho_pho Apr 13 '17 at 13:16

2 Answers2

0

Update the code as following

Declare a variable in the class as follows

var selectedImageViewIndex = 0 //by default selected image view is 0th image view


func selectImage(tap: UITapGestureRecognizer) {

    var imagePicker = UIImagePickerController()
    imagePicker.delegate = self
    imagePicker.sourceType = .photoLibrary
    imagePicker.allowsEditing = false
    imagePicker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
    self.present(imagePicker, animated: true, completion: nil)

    guard let viewTappedTag = tap.view?.tag else {return}

    self.selectedImageView = imageViews[viewTappedTag - 1] 

    //Add the following line
    self.selectedImageViewIndex = viewTappedTag - 1

}



func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

    var chosenImage = UIImage()
    chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
    self.selectedImageView.image = chosenImage

    //Add the following line
    self.imageView[self.selectedImageViewIndex].image = chosenImage
    dismiss(animated: true, completion: nil)

}

Though I would advice not to use viewTappedTag - 1 and instead get the value of index and tapped image tag from a mapped object.

Mukul More
  • 554
  • 2
  • 5
  • 18
  • Hi @Mukul More, this wont work as the type of your variable 'selectedImageViewIndex' is an integer and the collection outlet 'imageViews' is an array of UIImageViews.Therefore, there is a type clash in your line 'self.selectedImageViewIndex = imageViews[viewTappedTag - 1]' as this will return a UIImageView, not an integer. – pho_pho Apr 13 '17 at 14:28
  • Change it to. self.selectedImageViewIndex = viewTappedTag - 1. – Mukul More Apr 13 '17 at 14:30
  • Accessing the image view through their position in the outlet collection array is not a good way to do it as their position is arbritrary: http://stackoverflow.com/questions/14848599/how-can-i-orderly-arrange-items-in-referencing-outlet-collection-automatically see my solution above with the switch statement which appears to be a better solution – pho_pho Apr 13 '17 at 14:41
  • That's why I recommended using a map. There are always different ways to do things. – Mukul More Apr 13 '17 at 14:50
0

In the end I used a switch statement to achieve my goal:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

var chosenImage = UIImage()
chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage

switch self.viewTappedTag {
case 1:
    imageViewOne.image = chosenImage
case 2:
    imageViewTwo.image = chosenImage
case 3:
    imageViewThree.image = chosenImage
case 4:
    imageViewFour.image = chosenImage
default:
    imageViewOne.image = chosenImage

}

dismiss(animated: true, completion: nil)

}
pho_pho
  • 672
  • 11
  • 30