简体   繁体   中英

Swift - creating a UIPickerView within a UIStackView PROGRAMMATICALLY

I'm a complete beginner to swift & iOS dev in general, so be easy on me :)
In my app, I have a horizontal StackView.
Within that StackView - I have a label and a button , and now I would like to add a PickerView that would be populated from some list of options .
I've been googling and reading threads, but the closest I've gotten was getting the PickerView to show its position (using some background color) but with no actual values inside .
This is the code where I create and customize my StackView's components:

class SingleReportInputStackView: UIStackView {
    ...  // creating and customizing my StackView


    private func getObjects() -> (UILabel, UIButton, UIPickerView) {
        let myLabel: UILabel = {
            ...  // creating UILabel
        }()
        
        let myButton: UIButton = {
            ... // creating UIButton
        }()
        
        class MyPicker: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
            let dataArray = ["English", "Maths", "History", "German", "Science"]
            let UIPicker: UIPickerView = UIPickerView()
            
            override init() {
                super.init()
                self.UIPicker.delegate = self
                self.UIPicker.dataSource = self
                self.UIPicker.backgroundColor = UIColor.white
            }
            
            func numberOfComponents(in pickerView: UIPickerView) -> Int {
                return 1
            }
            
            func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
                return dataArray.count
            }
            
            func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
                let row = dataArray[row]
                return row
            }
        }
        
        let myPicker = MyPicker()
        return (myLabel, myButton, myPicker.UIPicker)
    }
    ...
}

Then, I add those components to my Horizontal StackView by calling setupSingleInput() :

class SingleReportInputStackView: UIStackView {
    ...
    private func setupSingleInput() {
        let (myLabel, myButton, myPicker) = getObjects()
        self.addArrangedSubview(myLabel)
        self.addArrangedSubview(myButton)
        self.addArrangedSubview(myPicker)
        self.translatesAutoresizingMaskIntoConstraints = false
    }
    ...
}

As I've said, I can see the label, the button and the PickerView's white background (looks like an empty, white rectangle).

BTW, I don't have a storyboard (if that wasn't obvious already) - I'm creating the UI programatically.

Can someone help me out? Why is my PickerView not being properly populated by my dataArray?

I'm a complete beginner to swift & iOS dev in general ...

I'd recommend starting a bit simpler... embedding a class inside a func is almost certainly not the way to go here.

The biggest problem is that you create an instance of MyPicker inside your getObjects() func, but then you return a UI element from that class, and the class instance goes away -- it goes out of scope :

private func getObjects() -> (UILabel, UIButton, UIPickerView) {
    // ... all the stuff you're doing in here

    let myPicker = MyPicker()

    // as soon as you return, myPicker no longer exists!!!

    return (myLabel, myButton, myPicker.UIPicker)
}

So, you have returned a UIPickerView , but it no longer has any code (its Delegate and DataSource) backing it.

Here's a quick modification:

class SingleReportInputStackView: UIStackView {
    
    private var myPicker: MyPicker!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupSingleInput()
    }
    required init(coder: NSCoder) {
        super.init(coder: coder)
        setupSingleInput()
    }
    private func setupSingleInput() {
        let (myLabel, myButton) = getObjects()
        myPicker = MyPicker()
        self.addArrangedSubview(myLabel)
        self.addArrangedSubview(myButton)
        self.addArrangedSubview(myPicker.UIPicker)
        self.translatesAutoresizingMaskIntoConstraints = false
    }
    
    private func getObjects() -> (UILabel, UIButton) {
        let myLabel: UILabel = {
            let v = UILabel()
            v.text = "The Label"
            return v
        }()
        
        let myButton: UIButton = {
            let v = UIButton(type: .system)
            v.setTitle("The Button", for: [])
            return v
        }()
        
        return (myLabel, myButton)
    }
    
    private class MyPicker: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
        let dataArray = ["English", "Maths", "History", "German", "Science"]
        let UIPicker: UIPickerView = UIPickerView()
        
        override init() {
            super.init()
            self.UIPicker.delegate = self
            self.UIPicker.dataSource = self
            self.UIPicker.backgroundColor = UIColor.white
        }
        
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return 1
        }
        
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            return dataArray.count
        }
        
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            let row = dataArray[row]
            return row
        }
    }
    
}

and a sample view controller to try it:

class UriYakirViewController: UIViewController {
    
    let singleReportStack = SingleReportInputStackView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // a yellow-ish background so we can see the white picker view frame
        view.backgroundColor = UIColor(red: 1.0, green: 0.8, blue: 0.5, alpha: 1)
        
        view.addSubview(singleReportStack)
        
        singleReportStack.axis = .vertical
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            singleReportStack.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            singleReportStack.centerYAnchor.constraint(equalTo: g.centerYAnchor),
        ])
        
    }
    
}

That code will give you this result:

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM