UIDatePicker expand & collapse

How do you expand/collapse a UIDatePicker?


I can do

datePicker.hidden = true

to hide it but it still occupies the space and the fields below it are not auto adjusted up to take up that space. Thanks

Answered by rockhammer in 148961022

Thanks, guywithmazda, your suggestion turns out to be the right general direction.


To back track a bit, the Apple recommended method to make this happen is to put everything in a tableView. So in one cell you have a label showing a picked date and then the cell just below the datePicker that gets hidden by hiding/unhiding the cell as needed. I was halfway into trying that when someone on stackoverflow suggested an alternate way is to put a height constraint on the datePicker, get an IBOutlet of that constraint into viewController and dynamically set the constraint to zero (hide) or X (open) as needed. It actually works and here is the code.


First, I have a relatively generic form in my viewController continaing: a "label" for the date to be picked (see details below), followed by the datePicker, followed by a number of other text fields below. I set both a height constraint for the datePicker and a top/bottom constraint between the date label & the datePicker. Then ctrl-drag each of these constraints into the viewController.swift file like so:


@IBOutlet weak var datePickerHeight: NSLayoutConstraint!
@IBOutlet weak var datePickerMarginTop: NSLayoutConstraint!


I have a state variable defined within the viewController class & some constants specifying the dimensions I want:


var datePickerOpened: Bool = false    // state variable
let datePickerHeightOpened: CGFloat = 214
let datePickerHeightClosed: CGFloat = 0
let datePickerMarginTopOpened: CGFloat = 0  // 18 (see below)
let datePickerMarginTopClosed: CGFloat = 0
let animateTimeStd: NSTimeInterval = 0.5
let animateTimeZero: NSTimeInterval = 0.0

Then I have this function defined to handle opening & hiding the datePicker:

func showDatePicker(show: Bool, animateTime: NSTimeInterval) {
        // set state variable
        datePickerOpened = show

        // this makes the datePicker disappear from the screen BUT leaves the space still occupied
        // this is not strictly necessary but it will make the appearance more tidy
        self.datePicker.hidden = !show

        // animate the datePicker open/hide - this is the where the constraints are modified
        UIView.animateWithDuration(animateTime, animations: {
      
            // toggle open/close the datePicker
            self.datePickerHeight.constant = (show ? self.datePickerHeightOpened : self.datePickerHeightClosed)
      
            // toggle open/close the datePicker top margin
            // as it turns out for me, it looked better in my set up to have top margin zero all the time but I'm leaving the code here in case I need it later
            self.datePickerMarginTop.constant = (show ? self.datePickerMarginTopOpened : self.datePickerMarginTopClosed)
      
            // this I understand tells the view to update
            self.view.layoutIfNeeded()
       })
}


Then in viewDidLoad(), ie in initial view load, I tell the datePicker to hide & do it without animation (otherwise there is an annoying flicker):


showDatePicker(false, animateTime: animateTimeZero)


For me, the "label" showing the date picked is actually a button. At the outset I just thought that would be the easiest way to make a datePicker open/hide. I could just as well have used an actual UILabel or a UITextField. Just the mechanism to invoke the datePicker would be somewhat different I guess. So my IBAction for that button is simply the following which uses the datePickerOpened state variable to toggle and specifies the open/hide to be animated:


@IBAction func dueDateAction(sender: AnyObject) {
    showDatePicker(!datePickerOpened, animateTime: animateTimeStd)
}


And, voila! I can make a datePicker disappear without resorting to tableView!

Didn't test, but perhaps set it's frame.size.height to 0 and/or modify it's constraints to make it's height 0?

Accepted Answer

Thanks, guywithmazda, your suggestion turns out to be the right general direction.


To back track a bit, the Apple recommended method to make this happen is to put everything in a tableView. So in one cell you have a label showing a picked date and then the cell just below the datePicker that gets hidden by hiding/unhiding the cell as needed. I was halfway into trying that when someone on stackoverflow suggested an alternate way is to put a height constraint on the datePicker, get an IBOutlet of that constraint into viewController and dynamically set the constraint to zero (hide) or X (open) as needed. It actually works and here is the code.


First, I have a relatively generic form in my viewController continaing: a "label" for the date to be picked (see details below), followed by the datePicker, followed by a number of other text fields below. I set both a height constraint for the datePicker and a top/bottom constraint between the date label & the datePicker. Then ctrl-drag each of these constraints into the viewController.swift file like so:


@IBOutlet weak var datePickerHeight: NSLayoutConstraint!
@IBOutlet weak var datePickerMarginTop: NSLayoutConstraint!


I have a state variable defined within the viewController class & some constants specifying the dimensions I want:


var datePickerOpened: Bool = false    // state variable
let datePickerHeightOpened: CGFloat = 214
let datePickerHeightClosed: CGFloat = 0
let datePickerMarginTopOpened: CGFloat = 0  // 18 (see below)
let datePickerMarginTopClosed: CGFloat = 0
let animateTimeStd: NSTimeInterval = 0.5
let animateTimeZero: NSTimeInterval = 0.0

Then I have this function defined to handle opening & hiding the datePicker:

func showDatePicker(show: Bool, animateTime: NSTimeInterval) {
        // set state variable
        datePickerOpened = show

        // this makes the datePicker disappear from the screen BUT leaves the space still occupied
        // this is not strictly necessary but it will make the appearance more tidy
        self.datePicker.hidden = !show

        // animate the datePicker open/hide - this is the where the constraints are modified
        UIView.animateWithDuration(animateTime, animations: {
      
            // toggle open/close the datePicker
            self.datePickerHeight.constant = (show ? self.datePickerHeightOpened : self.datePickerHeightClosed)
      
            // toggle open/close the datePicker top margin
            // as it turns out for me, it looked better in my set up to have top margin zero all the time but I'm leaving the code here in case I need it later
            self.datePickerMarginTop.constant = (show ? self.datePickerMarginTopOpened : self.datePickerMarginTopClosed)
      
            // this I understand tells the view to update
            self.view.layoutIfNeeded()
       })
}


Then in viewDidLoad(), ie in initial view load, I tell the datePicker to hide & do it without animation (otherwise there is an annoying flicker):


showDatePicker(false, animateTime: animateTimeZero)


For me, the "label" showing the date picked is actually a button. At the outset I just thought that would be the easiest way to make a datePicker open/hide. I could just as well have used an actual UILabel or a UITextField. Just the mechanism to invoke the datePicker would be somewhat different I guess. So my IBAction for that button is simply the following which uses the datePickerOpened state variable to toggle and specifies the open/hide to be animated:


@IBAction func dueDateAction(sender: AnyObject) {
    showDatePicker(!datePickerOpened, animateTime: animateTimeStd)
}


And, voila! I can make a datePicker disappear without resorting to tableView!

I wrote a library for this almost 8 years ago called "DatePickerCell". Not sure it works at the moment, but there's no open issues so it's possible.

https://github.com/DylanVann/DatePickerCell

UIDatePicker expand & collapse
 
 
Q