I wanted to create a smallest UIPickerView that looks good in portrait and landscape format, and it worked ... sort of. I add the pickerView after pushing a button, and hide it when done. The pickerView works correctly:
But it doesn't work well when launching in one orientation and changing orientation before clicking the button to show the pickerView, it then displays this sort of things: in portait orientation in paysage orientation
Here is the code (Single View Application, with just a button in the storyboard : myButton, with touch down action touchMyButton)
class myViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
@IBOutlet weak var myButton: UIButton!
var myPickerView: UIPickerView! = UIPickerView(frame:CGRectMake(0.0, 0.0, UIScreen.mainScreen().bounds.width, 162))
var activePickerView: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
myPickerView.tag = 1
myPickerView.delegate = self
myPickerView.autoresizingMask = [.FlexibleWidth]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@IBAction func touchMyButton(sender: AnyObject) {
if (activePickerView == 0)
{
activePickerView = myPickerView.tag
myPickerView.selectRow(5, inComponent:0, animated:false)
myPickerView.backgroundColor = UIColor.init(white:0.80, alpha:0.80)
myPickerView.frame = CGRectMake(0.0, 100.0, UIScreen.mainScreen().bounds.width, 0.0)
self.view.layoutIfNeeded()
self.view.addSubview(myPickerView)
myPickerView.setNeedsDisplay()
UIView.animateWithDuration(0.5, delay:0.0, options:UIViewAnimationOptions.CurveEaseInOut, animations:{
self.view.layoutIfNeeded()
self.myPickerView.frame = CGRectMake(0.0, 100.0, self.myPickerView.frame.width, 162)
}, completion: { _ in
})
}
else
{
self.selectPickerView()
}
}
func selectPickerView(){
if (activePickerView == myPickerView.tag)
{
let _ = myPickerView.selectedRowInComponent(0)
let framePV = self.myPickerView.frame
UIView.animateWithDuration(0.5, delay:0.0, options:UIViewAnimationOptions.CurveEaseInOut, animations:{
self.view.layoutIfNeeded()
self.myPickerView.frame = CGRectMake(0.0, framePV.origin.y, framePV.width, 0.0 )
}, completion:{ _ in
self.myPickerView.removeFromSuperview()
})
}
activePickerView = 0
}
// MARK: UIPickerViewDataSource methods
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int
{ return 1 }
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{ return 10 }
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{ return "Row \(row)" }
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
activePickerView = pickerView.tag
selectPickerView()
}
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation)
{ self.view.layoutIfNeeded() }
}
I'm lost, I don't see what I can change to make it work
Thanks, I did it with constraint (it's just not very simple), like that
import UIKit
class myViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
@IBOutlet weak var myButton: UIButton!
var myPickerView: UIPickerView! = UIPickerView()
var activePickerView: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
myPickerView.tag = 1
myPickerView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@IBAction func touchMyButton(sender: AnyObject) {
if (activePickerView == 0){
activePickerView = myPickerView.tag
myPickerView.selectRow(5, inComponent:0, animated:false)
myPickerView.backgroundColor = UIColor.init(white:0.80, alpha:0.80)
myPickerView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(myPickerView)
let margins = self.view.layoutMarginsGuide
let topC = myPickerView.topAnchor.constraintEqualToAnchor(topLayoutGuide.topAnchor, constant: 100.0)
let leadingC = myPickerView.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor)
let trailingC = myPickerView.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor)
let heightC = myPickerView.heightAnchor.constraintEqualToConstant(0.0)
heightC.identifier = "height"
NSLayoutConstraint.activateConstraints([topC, leadingC, trailingC, heightC])
self.view.layoutIfNeeded()
myPickerView.setNeedsLayout()
heightC.constant = 162.0
UIView.animateWithDuration(0.5, delay:0.0, options:UIViewAnimationOptions.CurveEaseInOut, animations:{
self.view.layoutIfNeeded()
}, completion: { _ in
})
}
else {
self.selectPickerView()
}
}
func selectPickerView(){
if (activePickerView == myPickerView.tag)
{
let _ = myPickerView.selectedRowInComponent(0)
for constraint in myPickerView.constraints
{
if constraint.identifier == "height"
{ constraint.constant = 0.0 }
}
myPickerView.setNeedsLayout()
UIView.animateWithDuration(0.5, delay:0.0, options:UIViewAnimationOptions.CurveEaseInOut, animations:{
self.view.layoutIfNeeded()
}, completion:{ _ in
self.myPickerView.removeConstraints(self.myPickerView.constraints)
self.myPickerView.removeFromSuperview()
})
}
activePickerView = 0
}
// MARK: UIPickerViewDataSource methods
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int
{ return 1 }
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{ return 10 }
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{ return "Row \(row)" }
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
activePickerView = pickerView.tag
selectPickerView()
}
}
I don't like the animation that discards the pickerView (I don't know why it isn't the exact opposite of the one to display it), but it works. I'll probably change it using an opaque view to cover the pickerViewin the future.