updated date picker
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
891a816f55
commit
32a44a51b5
@ -30,8 +30,10 @@ open class DatePicker: EntryFieldBase {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Private Properties
|
// MARK: - Private Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
internal override var responder: UIResponder? { hiddenView }
|
||||||
|
internal var hiddenView = UITextView().with { $0.width(0) }
|
||||||
internal var minWidthDefault = 186.0
|
internal var minWidthDefault = 186.0
|
||||||
internal var popoverView: UIView!
|
internal var popoverView: UIScrollView!
|
||||||
internal var popoverVisible = false
|
internal var popoverVisible = false
|
||||||
internal var outsideTapGesture: UITapGestureRecognizer?
|
internal var outsideTapGesture: UITapGestureRecognizer?
|
||||||
internal var outsidePanGesture: UIPanGestureRecognizer?
|
internal var outsidePanGesture: UIPanGestureRecognizer?
|
||||||
@ -141,6 +143,7 @@ open class DatePicker: EntryFieldBase {
|
|||||||
}
|
}
|
||||||
controlStackView.addArrangedSubview(calendarIcon)
|
controlStackView.addArrangedSubview(calendarIcon)
|
||||||
controlStackView.addArrangedSubview(selectedDateLabel)
|
controlStackView.addArrangedSubview(selectedDateLabel)
|
||||||
|
controlStackView.addArrangedSubview(hiddenView)
|
||||||
return controlStackView
|
return controlStackView
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,25 +171,11 @@ open class DatePicker: EntryFieldBase {
|
|||||||
formatter.dateFormat = dateFormat.format
|
formatter.dateFormat = dateFormat.format
|
||||||
selectedDateLabel.text = formatter.string(from: date)
|
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 {
|
extension DatePicker {
|
||||||
|
|
||||||
private func showPopover() {
|
private func showPopover() {
|
||||||
guard let viewController = UIApplication.topViewController(), let parentView = viewController.view else { return }
|
guard let viewController = UIApplication.topViewController(), let parentView = viewController.view else { return }
|
||||||
|
|
||||||
if popoverVisible {
|
if popoverVisible {
|
||||||
hidePopoverView()
|
hidePopoverView()
|
||||||
} else {
|
} else {
|
||||||
@ -226,34 +215,33 @@ extension DatePicker {
|
|||||||
|
|
||||||
parentView.addSubview(overlayView)
|
parentView.addSubview(overlayView)
|
||||||
|
|
||||||
popoverView = UIView()
|
popoverView = UIScrollView()
|
||||||
popoverView.backgroundColor = .white
|
popoverView.backgroundColor = .green
|
||||||
popoverView.layer.cornerRadius = 10
|
popoverView.clipsToBounds = true
|
||||||
popoverView.layer.shadowColor = UIColor.black.cgColor
|
popoverView.backgroundColor = .clear
|
||||||
popoverView.layer.shadowOpacity = 0.2
|
|
||||||
popoverView.layer.shadowOffset = CGSize(width: 0, height: 5)
|
|
||||||
popoverView.layer.shadowRadius = 10
|
|
||||||
popoverView.isHidden = true
|
popoverView.isHidden = true
|
||||||
popoverView.addSubview(calendar)
|
popoverView.addSubview(calendar)
|
||||||
calendar.pinToSuperView()
|
calendar.pinToSuperView()
|
||||||
popoverView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
parentView.addSubview(popoverView)
|
parentView.addSubview(popoverView)
|
||||||
|
|
||||||
popoverView.width(calendar.frame.width)
|
|
||||||
popoverView.height(calendar.frame.height)
|
|
||||||
|
|
||||||
let spacing: CGFloat = 4
|
let spacing: CGFloat = 4
|
||||||
let (popoverX, popoverY) = calculatePopoverPosition(relativeTo: containerView, in: parentView, size: calendar.frame.size, with: spacing)
|
let popoverSize: CGSize = .init(width: calendar.frame.width, height: calendar.frame.height)
|
||||||
popoverView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: popoverX).isActive = true
|
popoverView.contentSize = CGSize(width: popoverSize.width, height: popoverSize.height)
|
||||||
popoverView.topAnchor.constraint(equalTo: parentView.topAnchor, constant: popoverY).isActive = true
|
|
||||||
|
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()
|
parentView.layoutIfNeeded()
|
||||||
popoverView.alpha = 0
|
popoverView.alpha = 0
|
||||||
popoverView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
|
popoverView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
|
||||||
popoverView.isHidden = false
|
popoverView.isHidden = false
|
||||||
popoverVisible = true
|
popoverVisible = true
|
||||||
|
_ = responder?.becomeFirstResponder()
|
||||||
UIView.animate(withDuration: 0.3,
|
updateContainerView()
|
||||||
|
UIView.animate(withDuration: 0.3,
|
||||||
delay: 0,
|
delay: 0,
|
||||||
usingSpringWithDamping: 0.8,
|
usingSpringWithDamping: 0.8,
|
||||||
initialSpringVelocity: 0.2,
|
initialSpringVelocity: 0.2,
|
||||||
@ -262,6 +250,10 @@ extension DatePicker {
|
|||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
popoverView.alpha = 1
|
popoverView.alpha = 1
|
||||||
popoverView.transform = CGAffineTransform.identity
|
popoverView.transform = CGAffineTransform.identity
|
||||||
|
if popoverSize.height > adjustedHeight {
|
||||||
|
popoverView.flashScrollIndicators()
|
||||||
|
}
|
||||||
|
UIAccessibility.post(notification: .layoutChanged, argument: calendar)
|
||||||
parentView.layoutIfNeeded()
|
parentView.layoutIfNeeded()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -270,10 +262,9 @@ extension DatePicker {
|
|||||||
private func hidePopoverView() {
|
private func hidePopoverView() {
|
||||||
overlayView.isHidden = true
|
overlayView.isHidden = true
|
||||||
overlayView.removeFromSuperview()
|
overlayView.removeFromSuperview()
|
||||||
|
|
||||||
outsideTapGesture = nil
|
outsideTapGesture = nil
|
||||||
outsidePanGesture = nil
|
outsidePanGesture = nil
|
||||||
UIView.animate(withDuration: 0.2,
|
UIView.animate(withDuration: 0.2,
|
||||||
animations: {[weak self] in
|
animations: {[weak self] in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
popoverView.alpha = 0
|
popoverView.alpha = 0
|
||||||
@ -283,17 +274,23 @@ extension DatePicker {
|
|||||||
popoverView.isHidden = true
|
popoverView.isHidden = true
|
||||||
popoverView.removeFromSuperview()
|
popoverView.removeFromSuperview()
|
||||||
popoverVisible = false
|
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 sourceFrameInParent = sourceView.convert(sourceView.bounds, to: parentView)
|
||||||
let parentBounds = parentView.bounds
|
let parentBounds = parentView.bounds
|
||||||
let popoverWidth: CGFloat = size.width
|
let safeAreaInsets = parentView.safeAreaInsets
|
||||||
let popoverHeight: CGFloat = size.height
|
let popoverWidth = size.width
|
||||||
|
let popoverHeight = size.height
|
||||||
|
|
||||||
var popoverX: CGFloat = 0
|
var popoverX: CGFloat = 0
|
||||||
var popoverY: CGFloat = 0
|
var popoverY: CGFloat = 0
|
||||||
|
var adjustedHeight = popoverHeight
|
||||||
|
|
||||||
// Calculate horizontal position
|
// Calculate horizontal position
|
||||||
if sourceFrameInParent.width < popoverWidth {
|
if sourceFrameInParent.width < popoverWidth {
|
||||||
@ -311,19 +308,34 @@ extension DatePicker {
|
|||||||
popoverX = sourceFrameInParent.midX - popoverWidth / 2
|
popoverX = sourceFrameInParent.midX - popoverWidth / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate vertical position
|
// Ensure the popover is within the parent's bounds horizontally
|
||||||
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
|
|
||||||
popoverX = max(0, min(popoverX, parentBounds.width - popoverWidth))
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user