How to use 2 UIPickerView's in one View Contro

2019-01-22 07:20发布

I have 2 UIPickerController's in one of View Controllers. I can get one to work, but when I add a second, my app crashes. Here is the code I use for one picker view:

import UIKit

class RegisterJobPosition: UIViewController, UIPickerViewDelegate{

@IBOutlet weak var positionLabel: UILabel!

var position = ["Lifeguard", "Instructor", "Supervisor"]

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

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

func pickerView(pickerView: UIPickerView!, numberOfRowsInComponent component: Int) -> Int
{
    return position.count
}

func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String!
{
    return position[row]
}

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

    positionLabel.text = position[row]
}
}

Now, how can I get a second controller to work? Say my second PickerView is called location (the other one is called position). I tried duplicating the code within the PickerView methods for location but it doesn't work.

I'm using Swift.

5条回答
啃猪蹄的小仙女
2楼-- · 2019-01-22 07:32

I think the biggest issue and different to Java is that Java easily allow for attributes to be passed through the constructor. e.g. you could declare class LocationDataSourceDelegate as generic and call it genericDataSourceDelegate and make the constructor accept and Array public genericDataSourceDelegate (String data[]) and be able to make one class where could just simply create objects of. You just instantiate it and pass location the constructor like genericDataSourceDelegate (location)

The problem with your model you will have to create as many delegate classes in one program which is a strain to your compiler.

查看更多
男人必须洒脱
3楼-- · 2019-01-22 07:37

I found this to work.

class SecondViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {

    @IBOutlet weak var textbox1: UILabel!
    @IBOutlet weak var textbox2: UILabel!

    @IBOutlet weak var dropdown1: UIPickerView!
    @IBOutlet weak var dropdown2: UIPickerView!

    var age = ["10-20", "20-30", "30-40"]
    var Gender = ["Male", "Female"]

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

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        var countrows : Int = age.count
        if pickerView == dropdown2 {
            countrows = self.Gender.count
        }

        return countrows
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        if pickerView == dropdown1 {
            let titleRow = age[row]
             return titleRow
        } else if pickerView == dropdown2 {
            let titleRow = Gender[row]
            return titleRow
        }

        return ""
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        if pickerView == dropdown1 {
            self.textbox1.text = self.age[row]
        } else if pickerView == dropdown2 {            
            self.textbox2.text = self.Gender[row]
        }
    }
}
查看更多
小情绪 Triste *
4楼-- · 2019-01-22 07:40

Here is my solution: - on the Storyboard, add 2 PickerView to your View - set the 1st picker´s tag as #1 & #2 for the 2nd picker under the Attributes Inspector - CTRL + drag from each picker to the top yellow View Controller icon and choose dataSource.Repeate the same choosing delegate - repeate the above for the other picker too - add pickerview & pickerviewdelegation to your ViewController class:

class ViewController: UIViewController,UIPickerViewDataSource,UIPickerViewDelegate {
  • in your ViewController class, create empty arrays for the pickers:

    var picker1Options = []
    var picker2Options = []
    
  • on viewDidLoad() method, populate the arrays with your content:

    picker1Options = ["Option 1","Option 2","Option 3","Option 4","Option 5"]
    picker2Options = ["Item 1","Item 2","Item 3","Item 4","Item 5"]
    
  • implement the delegate & pickerview methods:

    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        if (pickerView.tag == 1){
            return picker1Options.count
        }else{
            return picker2Options.count
        }
    }
    
    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
        if (pickerView.tag == 1){
            return "\(picker1Options[row])"
        }else{
            return "\(picker2Options[row])"
        }
    }
    

Enjoy, have fun and express your happiness with a positiveness sign.

查看更多
看我几分像从前
5楼-- · 2019-01-22 07:42

My background is in Android but my answer is very OOP. I would suggest creating different classes to implement the DataSource and Delegate like this:

class PositionDataSourceDelegate : NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
   var position = ["Lifeguard", "Instructor", "Supervisor"]
   var selectedPosition : String?

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

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
      return position.count
    }

    func pickerView(pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
       return position[row]
    }

    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
       selectedPosition = position[row]
    }
}

and then another one for the Location:

class LocationDataSourceDelegate : NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
   var location = ["Up", "Down", "Everywhere"]
   var selectedLocation : String?

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

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return location.count
    }

    func pickerView(pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
         return location[row]
    }

    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        selectedLocation = location[row]
   }
}

then in your RegisterJobPosition you need to create an instance of each:

let positionDSD = PositionDataSourceDelegate()
let locationDSD = LocationDataSourceDelegate()

and assign them to the pickers like this:

positionPicker.dataSource = positionDSD
positionPicker.delegate = positionDSD
locationPicker.dataSource = locationDSD
locationPicker.delegate = locationDSD

and you can access the selected position and location using:

positionDSD.selectedPosition 
locationDSD.selectedLocation

Hope this helps you and others and I'm also hoping for some constructive comments of why this is not "swifty"

查看更多
Summer. ? 凉城
6楼-- · 2019-01-22 07:45

Based on the information I have in the question, I'd say that you need to set up the data source & delegate methods to handle the ability to distinguish between which picker instance is calling them.

Using the tag property on the picker view is one strategy.

There should be some if/else or switch statements in the methods that have varying logic depending on whether it's the location or the position picker that's being referenced.

查看更多
登录 后发表回答