SubView in Rectangular View On Storyboard Does Not Display

I added a rectangular view object in InterfaceBuilder to the main view on a Storyboard - after connecting that rectangular view to my ViewController using an IBOutlet I then added a pickerView as a subView in this rectangular view.


With the IB configuraiton below and ViewController code below the picker view does not display.


  • Rectangular View Object added to StoryBoard
  • IB Outliet set in ViewControler file for rectangular view above @IBOutlet weak var setterCounterView: UIView!
  • var picker: UIPickerView! set in ViewController
  • class ViewController: UIViewController, UITextFieldDelegate, UIPickerViewDataSource, UIPickerViewDelegate --> picker data source and delegate set


override func viewDidLoad() {

super.viewDidLoad()

// Do any additional setup after loading the view, typically from a nib.

self.pauseButtonState.isEnabled = false

// Add the setterCounterView to the custom view region in main view

picker = UIPickerView()

picker.center = view.center

setterCounterView.addSubview(picker)

picker!.delegate = self

picker.isHidden = false

picker.setNeedsDisplay()

setterCounterView.setNeedsDisplay()

setterCounterView.bringSubview(toFront: picker)

self.view.bringSubview(toFront: setterCounterView)

}


// MARK: ---- UIPicker Data Source ----


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

if pickerView == setterCounterView{

return 1

}

return 0

}


func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {

if pickerView == setterCounterView{

return 10

}

return 0

}


func pickerView(_ pickerView: UIPickerView,

titleForRow row: Int,

forComponent component: Int) -> String?{

// return "\(row + 1)"

return String(row + 1)

}

Accepted Reply

Where do you set the picker frame size?

        picker.frame = CGRect(x: 10, y: 10, width: 100, height: 100)


And you should also set the data source (but should work without):

        picker!.dataSource = self



And your tests are wrong, in both

numberOfComponents(in pickerView: UIPickerView) and

pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int):


if pickerView == setterCounterView{

should be

if pickerView == picker {


Where do you want the picker to be ? At center of the setterCounterView ?

If so, its center is not the view center ; because its center is relative to its superview. So it is the bounds center of its superview.


Finally, bringToFront are useless.


So, your initialization should become :


        picker = UIPickerView()
        picker!.delegate = self
        picker!.dataSource = self
        picker.frame = CGRect(x: 10, y: 10, width: 100, height: 100)          // Or any size you want
        setterCounterView.addSubview(picker)
        picker.center = CGPoint(x: setterCounterView.bounds.midX, y: setterCounterView.bounds.midY)

Replies

Do you mean : the picker does not show ?


Normal, you do


        setterCounterView.bringSubview(toFront: picker)
        self.view.bringSubview(toFront: setterCounterView)


So, setterCounterView is at the front, hiding the picker.


Try to reverse order

        self.view.bringSubview(toFront: setterCounterView)
        setterCounterView.bringSubview(toFront: picker)


Note: why not create the picker in IB as well ? Don't forget to connect the delegates then.

I tested with a date picker inside a rectangular view, it works.

thanks Claude31 - I also thought there was an issue with the order of the subviews however, when I reversed the order (good suggestion), I still do not see the picker. The reason I want to do this programmatically into a rectangular view is because I need to change the contents of the rectangular view depending on app state.


I also added needsDisplay method calls but that didn't help - see below


override func viewDidLoad() {

super.viewDidLoad()

// Do any additional setup after loading the view, typically from a nib.

self.pauseButtonState.isEnabled = false

// Add the setterCounterView to the custom view region in main view

picker = UIPickerView()

picker.center = view.center

setterCounterView.addSubview(picker)

picker!.delegate = self

picker.isHidden = false

picker.setNeedsDisplay()

self.view.bringSubview(toFront: setterCounterView)

setterCounterView.bringSubview(toFront: picker)

setterCounterView.setNeedsDisplay()

self.view.setNeedsDisplay()


}

Where do you set the picker frame size?

        picker.frame = CGRect(x: 10, y: 10, width: 100, height: 100)


And you should also set the data source (but should work without):

        picker!.dataSource = self



And your tests are wrong, in both

numberOfComponents(in pickerView: UIPickerView) and

pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int):


if pickerView == setterCounterView{

should be

if pickerView == picker {


Where do you want the picker to be ? At center of the setterCounterView ?

If so, its center is not the view center ; because its center is relative to its superview. So it is the bounds center of its superview.


Finally, bringToFront are useless.


So, your initialization should become :


        picker = UIPickerView()
        picker!.delegate = self
        picker!.dataSource = self
        picker.frame = CGRect(x: 10, y: 10, width: 100, height: 100)          // Or any size you want
        setterCounterView.addSubview(picker)
        picker.center = CGPoint(x: setterCounterView.bounds.midX, y: setterCounterView.bounds.midY)

yeah, I was just working on adding a CGRect for the picker size when you responded.


I also had the picker centered in the view center and not the setterCounterView center ( changed picker.center = view.center to picker.center = setterCounterView.center) - but without setting the CGRect for the picker the frame size for the picker was 0!


Thanks for catching the test conditions as well.


Everything now works - picker is visible and moves with content.


Thanks

One additional thought, it would be nice if XCode had a preference that could be enabled to detect and display warnings for objects within views or subViews with zero size frames.