14

I am trying to use images in a Swift PickerView. I don't know how to get the images to actually appear in the component. I know how to do this using Strings with the titleForRow function but I don't know how to do this using images. Here is my code so far:

import UIKit
class ViewController: UIViewController, UIPickerViewDelegate {

    @IBOutlet weak var pickerView: UIPickerView!


    var imageArray: [UIImage] = [UIImage(named: "washington.jpg")!,
        UIImage(named: "berlin.jpg")!, UIImage(named: "beijing.jpg")!,
        UIImage(named: "tokyo.jpg")!]



    override func viewDidLoad() {
        super.viewDidLoad()
        // 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.
    }


    // returns the number of 'columns' to display.
    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int{

        return 1

    }

    // returns the # of rows in each component..
    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {

        return imageArray.count
    }



}// end of app
JeanLuc
  • 4,783
  • 1
  • 33
  • 47
Susan Starkman
  • 163
  • 1
  • 1
  • 7
  • 1
    if we have multiple pickerviews than there might be an issue comes because of viewForRow because not all pickerview's will have images only some and other some are normal pickerviews with text only than how can we achieve this?? – ArgaPK Feb 08 '18 at 12:41
  • I'm also confused on this @ArgaPK. Any help anyone?? – Eric33187 Apr 07 '21 at 04:58

5 Answers5

20

You will need to implement a couple more the delegate methods for the UIPickerViewDelegate protocol. In particular a rowHeight delegate method and a viewForRow delegate method.

Something like:

// MARK: UIPickerViewDataSource

func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
    return 1
}

func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return 2
}

 func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
    return 60
}


// MARK: UIPickerViewDelegate

func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView {

    var myView = UIView(frame: CGRectMake(0, 0, pickerView.bounds.width - 30, 60))

    var myImageView = UIImageView(frame: CGRectMake(0, 0, 50, 50))

    var rowString = String()
    switch row {
    case 0:
        rowString = “Washington”
        myImageView.image = UIImage(named:"washington.jpg")
    case 1:
        rowString = “Beijing”
        myImageView.image = UIImage(named:"beijing.jpg")
    case 2:
        default:
        rowString = "Error: too many rows"
        myImageView.image = nil
    }
    let myLabel = UILabel(frame: CGRectMake(60, 0, pickerView.bounds.width - 90, 60 ))
    myLabel.font = UIFont(name:some font, size: 18)
    myLabel.text = rowString

    myView.addSubview(myLabel)
    myView.addSubview(myImageView)

    return myView
}

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

   // do something with selected row
}

Note that the label layout etc is just for demonstration, would need to be tweaked, or probably better to use Auto Layout ect.

Shaun
  • 4,057
  • 7
  • 38
  • 48
Norman G
  • 759
  • 8
  • 18
  • Thank you! This is exacly what I was looking for. I figured I needed the viewForRow function but couldn't quite get it right. So appreciate your help. – Susan Starkman Jan 05 '15 at 01:02
  • I am trying to have two components each with an image. I can do this with Strings but when I use the above code (which works great for one component) I get the following error when creating the arrays within the array: UIImage does not have an member named "Element" – Susan Starkman Jan 12 '15 at 18:10
  • 1
    Is there a better way of going about this if I have 50 different images I want displayed? – Cyril Aug 24 '16 at 02:30
  • 1
    @NormanG if we have multiple pickerviews than there might be an issue comes because of viewForRow because not all pickerview's will have images only some and other some are normal pickerviews with text only than how can we achieve this?? – ArgaPK Feb 08 '18 at 12:41
2

I had this same question and did some research until I figured it out. Here's an example that works great for me. Just make sure your images in the Assets folder are all named the same as your case strings and you'll be set!

@IBOutlet weak var pickerView: UIPickerView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    pickerView.delegate = self
}

// MARK: UIPickerViewDataSource

func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
    return 1
}

func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return 11
}

// MARK: UIPickerViewDelegate

func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {


    var myImageView = UIImageView()

    switch row {
    case 0:
        myImageView = UIImageView(image: UIImage(named:"airplane"))
    case 1:
        myImageView = UIImageView(image: UIImage(named:"beach"))
    case 2:
        myImageView = UIImageView(image: UIImage(named:"bike"))
    case 3:
        myImageView = UIImageView(image: UIImage(named:"hiking"))
    case 4:
        myImageView = UIImageView(image: UIImage(named:"ironman"))
    case 5:
        myImageView = UIImageView(image: UIImage(named:"moneybag"))
    case 6:
        myImageView = UIImageView(image: UIImage(named:"moneybills"))
    case 7:
        myImageView = UIImageView(image: UIImage(named:"ninjaturtle"))
    case 8:
        myImageView = UIImageView(image: UIImage(named:"running"))
    case 9:
        myImageView = UIImageView(image: UIImage(named:"shoppingcart"))
    case 10:
        myImageView = UIImageView(image: UIImage(named:"workingout"))
    default:
        myImageView.image = nil

        return myImageView
    }
    return myImageView
}

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

    // do something with selected row
}
Daniel
  • 21
  • 3
  • 1
    if we have multiple pickerviews than there might be an issue comes because of viewForRow because not all pickerview's will have images only some and other some are normal pickerviews with text only than how can we achieve this?? – ArgaPK Feb 08 '18 at 12:42
2

Making switch statements could be tedious when dealing with a lot of stuff.

Instead, use a for loop like this

for _ in 1..<imageArray.count {
myImageView.image = UIImage(named: imageArray[row])

}
Cyril
  • 2,783
  • 1
  • 24
  • 35
  • 1
    if we have multiple pickerviews than there might be an issue comes because of viewForRow because not all pickerview's will have images only some and other some are normal pickerviews with text only than how can we achieve this?? – ArgaPK Feb 08 '18 at 12:42
0

You do not need to subclass UIPickerView (and in fact that is probably not a wise view to subclass anyhow). Instead you need to have an object that implements the UIPickerViewDelegate protocol. Within this object you would implement the method

optional func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView

This method provides the individual components' views. Within that method you would return the appropriate value from your image array.

Andrew Monshizadeh
  • 1,784
  • 11
  • 16
0
var pickerDataSource = [UIImage(named:"house-7"),UIImage(named:"house-7"),UIImage(named:"house-7"),UIImage(named:"house-7"),UIImage(named:"house-7")]   

func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
    let myImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 61))
    myImageView.image = pickerDataSource[row]
    return myImageView
}
David Buck
  • 3,752
  • 35
  • 31
  • 35
Khabbab_h
  • 19
  • 6