13

I'm trying to create an expandable/collapsible date picker (similar to Apple's date picker in the Date & Time section of the Settings app). I have a tableview that can have a button as one of its table cells. That button shows the currently picked date as its title. Tapping on that button will add a table cell below the button with the new iOS 14 inline date picker.

The issue I'm facing is that I can interact with the date picker by changing the month and year, but the selected day doesn't change when I tap on different days. I added a target on valueChanged and the selector method is triggered when I change the month and year, but not when I choose a different day.

I saw there was a similar question on StackOverflow, but the OP deleted it for some reason.

The table cell containing the date picker is simple. I am dequeueing the cell from its own xib and the xib only contains a view with the date picker inside it. I am not setting the height of the date picker cell, but just using UITableView.automaticDimension to get self-sizing cells. I also looked at the view hierarchy and there isn't anything in front of the date picker, so the touches should be sent to the date picker.

Has anyone else had this issue?

enter image description here

Alzeon
  • 283
  • 2
  • 9
  • Does the UI show the date press? – aheze Oct 02 '20 at 18:08
  • 1
    My guess is that you added the date picker to the _cell_ when you should have added it to the _content view_. – matt Oct 02 '20 at 18:09
  • @aheze What do you mean by date press? Like a highlighted state when the day is tapped? No, it doesn't show a highlighted state. Though, I don't think the date picker in the settings app shows the date press either. – Alzeon Oct 02 '20 at 18:12
  • Yeah, I meant the highlight state. No, the settings app adds a circle behind the selected day. – aheze Oct 02 '20 at 18:14
  • @matt That's a good point. I checked the xib file and the date picker is a subview of the content view (date picker wasn'tn a direct child of the cell itself). The view hierarchy also shows that the date picker is at least in front of the cell content view. I can interact with the date picker by choosing different months and years, but I can't choose the day for some reason. – Alzeon Oct 02 '20 at 18:18
  • 1
    Darn, it seemed like such a clever guess! – matt Oct 02 '20 at 18:21
  • Looking carefully at the view debugger, is the date picker partly outside of its superview (immediate or higher)? That is a typical cause of non-touchability. – matt Oct 02 '20 at 18:22
  • It looks like the month and year label (in the date picker) slightly overlaps the calendar/day view. – Alzeon Oct 02 '20 at 18:42
  • 1
    Same issue here. In my case I can select the different days, but only if I touch them for a couple of seconds. Moreover, if I try to select the time, the picker view changes (becomes bigger) and the month/year selector goes outside the top of the cell. Any help would be great. – Aleph72 Oct 15 '20 at 10:29

5 Answers5

11

Just had the same issue, my calendar worked fine initially and eventually stopped working, the UIDatePicker was inside a UIView added through storyboard inside The main View.

Everything worked fine and I could click on the month and year and swipe months left and right. But when trying to click on a day nothing would happen. A new selection could not be made.

In my case reason behind it was adding a tapGesture to my main view for hiding keyboard. This made the calendar days unselectable.

(https://i.stack.imgur.com/k4AKF.jpg)

Paul
  • 183
  • 1
  • 12
  • 2
    This was the correct answer for me. I had a tapGesture on my main view for hiding the keyboard, and removing that fixed it. – Michael Montalbano Feb 15 '21 at 18:17
  • 2
    Simple fix, but can leave you with many days to figure it out as there is no direct link, took me a week myself to realise it, glad I could help! – Paul Feb 23 '21 at 21:53
  • @Paul Did you find out how to use calendar and tap gesture simultaneously? – frank61003 May 19 '21 at 09:10
  • Instead of using the Tap Gesture on my entire main View, I have split the main view in to 2, one would contain the calendar and one would contain rest of the content, that way the non calendar view part could still be assigned the tap gesture. – Paul Jun 06 '21 at 14:02
  • I was struggling to find what was blocking me from selecting the days inside the calendar view. Strangely, double tap was working fine, it was single tap that was not allowing the days to be selected. Anyways, after removing tap gesture from storyboard the tap is now working. – GeekyDeveloper Dec 30 '21 at 18:29
2

I had the same issue. In my case problem was in UITapGestureRecognizer, which I've add to hide keyboard.

This code fixed my problem:

tapGesture.cancelsTouchesInView = false
1

I had the same issue, and on my side was a problem with how I was adding the picker inside of the cell.

Check you are doing self.contentView addSubview: not self addSubview.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/low-quality-posts/27459507) – Thingamabobs Oct 23 '20 at 19:39
  • @Atlas435: Please review [what is appropriate to delete as a _low quality post_](https://meta.stackoverflow.com/questions/287563/youre-doing-it-wrong-a-plea-for-sanity-in-the-low-quality-posts-queue). Monica is very much suggesting an answer. It may not be a _correct_ answer—I'm not in a position to evaluate it—but it's certainly an _attempt_ to provide an answer. Remember, the purpose of the review queue is to remove _blatant violations_ ("Thank you", "Me too", "But what about [x]?"); if you really think an answer is incorrect or not otherwise useful, that's what downvoting is for. – Jeremy Caney Oct 23 '20 at 20:05
1

In my case, I have a popup datepickerView with a mask in the background, and I want the datepickerView to disappear when I click background. So I added UITapGestureRecognizer in the background. I can't select the date in the datepicker after adding the gesture

Thanks to @Сергій Насінник, This code fixed my problem:

tapGesture.cancelsTouchesInView = false

import UIKit
import SnapKit

class PopUpDatePickerView: UIView {
    
    let contentView = UIView()
    let datePicker = UIDatePicker()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .black.withAlphaComponent(0.4)
        
        
        contentView.backgroundColor = .white
        contentView.layer.cornerRadius = 16
        addSubview(contentView)
        contentView.snp.makeConstraints { make in
            make.bottom.equalTo(self.safeAreaLayoutGuide).offset(-10)
            make.left.right.equalToSuperview().inset(5)
        }
        
        datePicker.tintColor = .black
        contentView.addSubview(datePicker)
        datePicker.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(20)
        }
        
        if #available(iOS 14.0, *) {
            datePicker.preferredDatePickerStyle = .inline
        }
        
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapHandler(_:)))
        tapGesture.cancelsTouchesInView = false
        addGestureRecognizer(tapGesture)
        
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    @objc func tapHandler(_ sender: UITapGestureRecognizer) {
        guard
            !self.contentView.frame.contains(sender.location(in: self))  else {
            return
        }
        removeFromSuperview()
    }
}

enter image description here

wlixcc
  • 1,132
  • 10
  • 14
0

Ok I found a work around to seemingly allow a tap gesture on the background view and still have the calendar working; the idea is to add 4 rectangular views around the calendar view and add your tap gesture to those 4 views.

Add a picker background view (I called mine datePickerBGView) to your main view and then add your UIDatePicker (I called mine picker) to this background view and assign the same center point to both views:

picker.center = datePickerBGView.center

Then call this function:

func addDismissGesture() {
    
    //Work around because with the .inline date picker style tap gestures on the background view interfere with the day selection action on the picker's calendar view
    let leftDismissActionTap = UITapGestureRecognizer(target: self, action: #selector(dismissCalendar))
    let rightDismissActionTap = UITapGestureRecognizer(target: self, action: #selector(dismissCalendar))
    let topDismissActionTap = UITapGestureRecognizer(target: self, action: #selector(dismissCalendar))
    let bottomDismissActionTap = UITapGestureRecognizer(target: self, action: #selector(dismissCalendar))
    let leftDismissArea = UIView()
    let rightDismissArea = UIView()
    let topDismissArea = UIView()
    let bottomDismissArea = UIView()

    leftDismissArea.frame = CGRect(x: 0, y: 0, width: picker.frame.minX - view.frame.minX, height: view.frame.height)
    rightDismissArea.frame = CGRect(x: picker.frame.maxX, y: 0, width: view.frame.maxX - picker.frame.maxX, height: view.frame.height)
    topDismissArea.frame = CGRect(x: leftDismissArea.frame.maxX, y: 0, width: rightDismissArea.frame.minX - leftDismissArea.frame.maxX, height: picker.frame.minY - view.frame.minY)
    bottomDismissArea.frame = CGRect(x: leftDismissArea.frame.maxX, y: picker.frame.maxY, width:rightDismissArea.frame.minX - leftDismissArea.frame.maxX, height:  view.frame.maxY - picker.frame.maxY)
    
    datePickerBGView.addSubview(leftDismissArea)
    datePickerBGView.addSubview(rightDismissArea)
    datePickerBGView.addSubview(topDismissArea)
    datePickerBGView.addSubview(bottomDismissArea)
    
    leftDismissArea.addGestureRecognizer(leftDismissActionTap)
    rightDismissArea.addGestureRecognizer(rightDismissActionTap)
    topDismissArea.addGestureRecognizer(topDismissActionTap)
    bottomDismissArea.addGestureRecognizer(bottomDismissActionTap)
    
    leftDismissArea.backgroundColor = UIColor.black.withAlphaComponent(0.3)
    rightDismissArea.backgroundColor = UIColor.black.withAlphaComponent(0.3)
    topDismissArea.backgroundColor = UIColor.black.withAlphaComponent(0.3)
    bottomDismissArea.backgroundColor = UIColor.black.withAlphaComponent(0.3)
    
    datePickerBGView.bringSubviewToFront(picker)
}
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
HannahSaud
  • 33
  • 5