updated date picker

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2024-06-24 15:34:02 -05:00
parent 891a816f55
commit 32a44a51b5

View File

@ -30,8 +30,10 @@ open class DatePicker: EntryFieldBase {
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
internal override var responder: UIResponder? { hiddenView }
internal var hiddenView = UITextView().with { $0.width(0) }
internal var minWidthDefault = 186.0
internal var popoverView: UIView!
internal var popoverView: UIScrollView!
internal var popoverVisible = false
internal var outsideTapGesture: UITapGestureRecognizer?
internal var outsidePanGesture: UIPanGestureRecognizer?
@ -141,6 +143,7 @@ open class DatePicker: EntryFieldBase {
}
controlStackView.addArrangedSubview(calendarIcon)
controlStackView.addArrangedSubview(selectedDateLabel)
controlStackView.addArrangedSubview(hiddenView)
return controlStackView
}
@ -168,25 +171,11 @@ open class DatePicker: EntryFieldBase {
formatter.dateFormat = dateFormat.format
selectedDateLabel.text = formatter.string(from: date)
}
internal var popoverController: ClearPopoverViewController?
func didSelect(_ date: Date) {
selectedDate = date
sendActions(for: .valueChanged)
UIAccessibility.post(notification: .layoutChanged, argument: self.containerView)
popoverController?.dismiss(animated: true){ [weak self] in
guard let self else { return }
popoverController = nil
}
}
}
extension DatePicker {
private func showPopover() {
guard let viewController = UIApplication.topViewController(), let parentView = viewController.view else { return }
if popoverVisible {
hidePopoverView()
} else {
@ -226,34 +215,33 @@ extension DatePicker {
parentView.addSubview(overlayView)
popoverView = UIView()
popoverView.backgroundColor = .white
popoverView.layer.cornerRadius = 10
popoverView.layer.shadowColor = UIColor.black.cgColor
popoverView.layer.shadowOpacity = 0.2
popoverView.layer.shadowOffset = CGSize(width: 0, height: 5)
popoverView.layer.shadowRadius = 10
popoverView = UIScrollView()
popoverView.backgroundColor = .green
popoverView.clipsToBounds = true
popoverView.backgroundColor = .clear
popoverView.isHidden = true
popoverView.addSubview(calendar)
calendar.pinToSuperView()
popoverView.translatesAutoresizingMaskIntoConstraints = false
parentView.addSubview(popoverView)
popoverView.width(calendar.frame.width)
popoverView.height(calendar.frame.height)
let spacing: CGFloat = 4
let (popoverX, popoverY) = calculatePopoverPosition(relativeTo: containerView, in: parentView, size: calendar.frame.size, with: spacing)
popoverView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: popoverX).isActive = true
popoverView.topAnchor.constraint(equalTo: parentView.topAnchor, constant: popoverY).isActive = true
let popoverSize: CGSize = .init(width: calendar.frame.width, height: calendar.frame.height)
popoverView.contentSize = CGSize(width: popoverSize.width, height: popoverSize.height)
let (popoverX, popoverY, adjustedHeight) = calculatePopoverPosition(relativeTo: containerView, in: parentView, size: popoverSize, with: spacing)
//let adjustedX = adjustedHeight != popoverSize.height ? popoverX - 10 : popoverX
let adjustedWidth = adjustedHeight != popoverSize.height ? popoverSize.width + 10 : popoverSize.width
popoverView.frame = CGRect(x: popoverX, y: popoverY, width: adjustedWidth, height: adjustedHeight)
parentView.layoutIfNeeded()
popoverView.alpha = 0
popoverView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
popoverView.isHidden = false
popoverVisible = true
UIView.animate(withDuration: 0.3,
_ = responder?.becomeFirstResponder()
updateContainerView()
UIView.animate(withDuration: 0.3,
delay: 0,
usingSpringWithDamping: 0.8,
initialSpringVelocity: 0.2,
@ -262,6 +250,10 @@ extension DatePicker {
guard let self else { return }
popoverView.alpha = 1
popoverView.transform = CGAffineTransform.identity
if popoverSize.height > adjustedHeight {
popoverView.flashScrollIndicators()
}
UIAccessibility.post(notification: .layoutChanged, argument: calendar)
parentView.layoutIfNeeded()
})
}
@ -270,10 +262,9 @@ extension DatePicker {
private func hidePopoverView() {
overlayView.isHidden = true
overlayView.removeFromSuperview()
outsideTapGesture = nil
outsidePanGesture = nil
UIView.animate(withDuration: 0.2,
UIView.animate(withDuration: 0.2,
animations: {[weak self] in
guard let self else { return }
popoverView.alpha = 0
@ -283,17 +274,23 @@ extension DatePicker {
popoverView.isHidden = true
popoverView.removeFromSuperview()
popoverVisible = false
responder?.resignFirstResponder()
setNeedsUpdate()
UIAccessibility.post(notification: .layoutChanged, argument: containerView)
}
}
private func calculatePopoverPosition(relativeTo sourceView: UIView, in parentView: UIView, size: CGSize, with spacing: CGFloat) -> (CGFloat, CGFloat) {
private func calculatePopoverPosition(relativeTo sourceView: UIView, in parentView: UIView, size: CGSize, with spacing: CGFloat) -> (CGFloat, CGFloat, CGFloat) {
let sourceFrameInParent = sourceView.convert(sourceView.bounds, to: parentView)
let parentBounds = parentView.bounds
let popoverWidth: CGFloat = size.width
let popoverHeight: CGFloat = size.height
let safeAreaInsets = parentView.safeAreaInsets
let popoverWidth = size.width
let popoverHeight = size.height
var popoverX: CGFloat = 0
var popoverY: CGFloat = 0
var adjustedHeight = popoverHeight
// Calculate horizontal position
if sourceFrameInParent.width < popoverWidth {
@ -311,19 +308,34 @@ extension DatePicker {
popoverX = sourceFrameInParent.midX - popoverWidth / 2
}
// Calculate vertical position
if sourceFrameInParent.origin.y > parentBounds.height / 2 {
// Show above
popoverY = sourceFrameInParent.minY - popoverHeight - spacing
} else {
// Show below
popoverY = sourceFrameInParent.maxY + spacing
}
// Ensure the popover is within the parent's bounds
// Ensure the popover is within the parent's bounds horizontally
popoverX = max(0, min(popoverX, parentBounds.width - popoverWidth))
return (popoverX, popoverY)
// Calculate vertical position and height
let availableSpaceAbove = sourceFrameInParent.minY - safeAreaInsets.top - spacing
let availableSpaceBelow = parentBounds.height - sourceFrameInParent.maxY - safeAreaInsets.bottom - spacing
let totalAvailableHeight = parentBounds.height - safeAreaInsets.top - safeAreaInsets.bottom
if availableSpaceAbove >= popoverHeight {
// Show above without adjusting height
popoverY = sourceFrameInParent.minY - popoverHeight - spacing
} else if availableSpaceBelow >= popoverHeight {
// Show below without adjusting height
popoverY = sourceFrameInParent.maxY + spacing
} else if totalAvailableHeight >= popoverHeight {
// check if the total
if availableSpaceAbove > availableSpaceBelow {
popoverY = safeAreaInsets.top
} else {
popoverY = parentBounds.height - safeAreaInsets.bottom - popoverHeight
}
} else {
popoverY = safeAreaInsets.top
adjustedHeight = totalAvailableHeight
}
return (popoverX, popoverY, adjustedHeight)
}
}