testing not using popover viewcontroller
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
ce6aad5540
commit
aad70d2e40
@ -19,6 +19,10 @@ open class ClearPopoverViewController: UIViewController, UIPopoverPresentationCo
|
|||||||
/// Popover presentation controller of the popover
|
/// Popover presentation controller of the popover
|
||||||
private var popOver: UIPopoverPresentationController!
|
private var popOver: UIPopoverPresentationController!
|
||||||
|
|
||||||
|
open var maxWidth: CGFloat?
|
||||||
|
|
||||||
|
open var sourceRect: CGRect?
|
||||||
|
|
||||||
open var spacing: CGFloat = 0
|
open var spacing: CGFloat = 0
|
||||||
/**
|
/**
|
||||||
A controller that manages the popover.
|
A controller that manages the popover.
|
||||||
@ -35,6 +39,7 @@ open class ClearPopoverViewController: UIViewController, UIPopoverPresentationCo
|
|||||||
self.contentView = contentView
|
self.contentView = contentView
|
||||||
self.spacing = spacing
|
self.spacing = spacing
|
||||||
self.arrow = arrow
|
self.arrow = arrow
|
||||||
|
self.sourceRect = sourceRect
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
setupPopover(sourceView, sourceRect, barButtonItem)
|
setupPopover(sourceView, sourceRect, barButtonItem)
|
||||||
}
|
}
|
||||||
@ -65,7 +70,6 @@ open class ClearPopoverViewController: UIViewController, UIPopoverPresentationCo
|
|||||||
popOver.popoverBackgroundViewClass = ClearPopoverBackgroundView.self
|
popOver.popoverBackgroundViewClass = ClearPopoverBackgroundView.self
|
||||||
popOver.sourceView = sourceView
|
popOver.sourceView = sourceView
|
||||||
popOver.popoverLayoutMargins = .zero
|
popOver.popoverLayoutMargins = .zero
|
||||||
|
|
||||||
if let sourceRect = sourceRect {
|
if let sourceRect = sourceRect {
|
||||||
popOver.sourceRect = sourceRect
|
popOver.sourceRect = sourceRect
|
||||||
}
|
}
|
||||||
@ -85,11 +89,8 @@ open class ClearPopoverViewController: UIViewController, UIPopoverPresentationCo
|
|||||||
|
|
||||||
private func updatePopoverPosition() {
|
private func updatePopoverPosition() {
|
||||||
guard let popoverPresentationController = popoverPresentationController else { return }
|
guard let popoverPresentationController = popoverPresentationController else { return }
|
||||||
if let sourceView = popoverPresentationController.sourceView {
|
if let sourceView = popoverPresentationController.sourceView, let sourceRect {
|
||||||
popoverPresentationController.sourceRect = .init(x: sourceView.bounds.origin.x,
|
popoverPresentationController.sourceRect = sourceRect
|
||||||
y: sourceView.bounds.origin.y,
|
|
||||||
width: sourceView.bounds.width,
|
|
||||||
height: sourceView.bounds.height + spacing)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -117,10 +117,11 @@ open class DatePicker: EntryFieldBase {
|
|||||||
|
|
||||||
NotificationCenter.default
|
NotificationCenter.default
|
||||||
.publisher(for: UIDevice.orientationDidChangeNotification).sink { [weak self] _ in
|
.publisher(for: UIDevice.orientationDidChangeNotification).sink { [weak self] _ in
|
||||||
guard let self, let popoverController else { return }
|
guard let self else { return }
|
||||||
popoverController.dismiss(animated: true){ [weak self] in
|
popoverController?.dismiss(animated: true){ [weak self] in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
}
|
}
|
||||||
|
hidePopoverView()
|
||||||
}
|
}
|
||||||
.store(in: &subscribers)
|
.store(in: &subscribers)
|
||||||
|
|
||||||
@ -163,7 +164,7 @@ open class DatePicker: EntryFieldBase {
|
|||||||
selectedDateLabel.text = formatter.string(from: date)
|
selectedDateLabel.text = formatter.string(from: date)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal var popoverController: UIViewController?
|
internal var popoverController: ClearPopoverViewController?
|
||||||
|
|
||||||
func didSelect(_ date: Date) {
|
func didSelect(_ date: Date) {
|
||||||
selectedDate = date
|
selectedDate = date
|
||||||
@ -175,34 +176,179 @@ open class DatePicker: EntryFieldBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func togglePicker() {
|
private var overlayView = UIView().with {
|
||||||
let calendar = CalendarBase()
|
$0.backgroundColor = .clear;
|
||||||
calendar.activeDates = calendarModel.activeDates
|
$0.isHidden = true
|
||||||
calendar.hideContainerBorder = calendarModel.hideContainerBorder
|
}
|
||||||
calendar.hideCurrentDateIndicator = calendarModel.hideCurrentDateIndicator
|
private var popoverView: UIView!
|
||||||
calendar.inactiveDates = calendarModel.inactiveDates
|
private var popoverVisible = false
|
||||||
calendar.indicators = calendarModel.indicators
|
private var outsideTapGesture: UITapGestureRecognizer?
|
||||||
calendar.maxDate = calendarModel.maxDate
|
private var outsidePanGesture: UIPanGestureRecognizer?
|
||||||
calendar.minDate = calendarModel.minDate
|
|
||||||
calendar.surface = calendarModel.surface
|
// internal func togglePicker() {
|
||||||
calendar.setNeedsLayout()
|
// calendar.activeDates = calendarModel.activeDates
|
||||||
calendar.layoutIfNeeded()
|
// calendar.hideContainerBorder = calendarModel.hideContainerBorder
|
||||||
calendar.onChange = { [weak self] control in
|
// calendar.hideCurrentDateIndicator = calendarModel.hideCurrentDateIndicator
|
||||||
guard let self else { return }
|
// calendar.inactiveDates = calendarModel.inactiveDates
|
||||||
didSelect(control.selectedDate)
|
// calendar.indicators = calendarModel.indicators
|
||||||
}
|
// calendar.maxDate = calendarModel.maxDate
|
||||||
|
// calendar.minDate = calendarModel.minDate
|
||||||
|
// calendar.surface = calendarModel.surface
|
||||||
|
// calendar.setNeedsLayout()
|
||||||
|
// calendar.layoutIfNeeded()
|
||||||
|
// calendar.onChange = { [weak self] control in
|
||||||
|
// guard let self else { return }
|
||||||
|
// didSelect(control.selectedDate)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// popoverController = ClearPopoverViewController(contentView: calendar,
|
||||||
|
// arrow: .any,
|
||||||
|
// sourceView: containerView,
|
||||||
|
// sourceRect: .init(x: 0, y: 0, width: 320, height: 45),
|
||||||
|
// spacing: VDSLayout.space1X)
|
||||||
|
// popoverController?.maxWidth = 320
|
||||||
|
// if let viewController = UIApplication.topViewController(), let popoverController {
|
||||||
|
// viewController.present(popoverController,
|
||||||
|
// animated: true,
|
||||||
|
// completion: nil)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DatePicker {
|
||||||
|
|
||||||
|
private func togglePicker() {
|
||||||
|
guard let viewController = UIApplication.topViewController(), let parentView = viewController.view else { return }
|
||||||
|
|
||||||
|
if popoverVisible {
|
||||||
|
hidePopoverView()
|
||||||
|
} else {
|
||||||
|
let calendar = CalendarBase()
|
||||||
|
calendar.activeDates = calendarModel.activeDates
|
||||||
|
calendar.hideContainerBorder = calendarModel.hideContainerBorder
|
||||||
|
calendar.hideCurrentDateIndicator = calendarModel.hideCurrentDateIndicator
|
||||||
|
calendar.inactiveDates = calendarModel.inactiveDates
|
||||||
|
calendar.indicators = calendarModel.indicators
|
||||||
|
calendar.maxDate = calendarModel.maxDate
|
||||||
|
calendar.minDate = calendarModel.minDate
|
||||||
|
calendar.surface = calendarModel.surface
|
||||||
|
calendar.setNeedsLayout()
|
||||||
|
calendar.layoutIfNeeded()
|
||||||
|
calendar.onChange = { [weak self] control in
|
||||||
|
guard let self else { return }
|
||||||
|
selectedDate = control.selectedDate
|
||||||
|
sendActions(for: .valueChanged)
|
||||||
|
UIAccessibility.post(notification: .layoutChanged, argument: containerView)
|
||||||
|
hidePopoverView()
|
||||||
|
}
|
||||||
|
|
||||||
|
outsideTapGesture = UITapGestureRecognizer()
|
||||||
|
outsidePanGesture = UIPanGestureRecognizer()
|
||||||
|
|
||||||
|
overlayView.publisher(for: outsideTapGesture!).sink { [weak self] _ in
|
||||||
|
guard let self else { return }
|
||||||
|
hidePopoverView()
|
||||||
|
}.store(in: &subscribers)
|
||||||
|
parentView.publisher(for: outsidePanGesture!).sink { [weak self] _ in
|
||||||
|
guard let self else { return }
|
||||||
|
hidePopoverView()
|
||||||
|
}.store(in: &subscribers)
|
||||||
|
|
||||||
|
overlayView.frame = parentView.bounds
|
||||||
|
overlayView.isHidden = false
|
||||||
|
|
||||||
|
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.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
|
||||||
|
|
||||||
|
parentView.layoutIfNeeded()
|
||||||
|
popoverView.alpha = 0
|
||||||
|
popoverView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
|
||||||
|
popoverView.isHidden = false
|
||||||
|
popoverVisible = true
|
||||||
|
|
||||||
popoverController = ClearPopoverViewController(contentView: calendar,
|
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.2, options: .curveEaseOut, animations: { [weak self] in
|
||||||
arrow: .up,
|
guard let self else { return }
|
||||||
sourceView: containerView,
|
popoverView.alpha = 1
|
||||||
sourceRect: containerView.bounds,
|
popoverView.transform = CGAffineTransform.identity
|
||||||
spacing: VDSLayout.space1X)
|
parentView.layoutIfNeeded()
|
||||||
|
})
|
||||||
if let viewController = UIApplication.topViewController(), let popoverController {
|
|
||||||
viewController.present(popoverController,
|
|
||||||
animated: true,
|
|
||||||
completion: nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func hidePopoverView() {
|
||||||
|
overlayView.isHidden = true
|
||||||
|
overlayView.removeFromSuperview()
|
||||||
|
|
||||||
|
outsideTapGesture = nil
|
||||||
|
outsidePanGesture = nil
|
||||||
|
UIView.animate(withDuration: 0.2, animations: {
|
||||||
|
self.popoverView.alpha = 0
|
||||||
|
self.popoverView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
|
||||||
|
}) { _ in
|
||||||
|
self.popoverView.isHidden = true
|
||||||
|
self.popoverView.removeFromSuperview()
|
||||||
|
self.popoverVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func calculatePopoverPosition(relativeTo sourceView: UIView, in parentView: UIView, size: CGSize, with spacing: 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
|
||||||
|
|
||||||
|
var popoverX: CGFloat = 0
|
||||||
|
var popoverY: CGFloat = 0
|
||||||
|
|
||||||
|
// Calculate horizontal position
|
||||||
|
if sourceFrameInParent.width < popoverWidth {
|
||||||
|
if sourceFrameInParent.midX - popoverWidth / 2 < 0 {
|
||||||
|
// Align to left
|
||||||
|
popoverX = sourceFrameInParent.minX
|
||||||
|
} else if sourceFrameInParent.midX + popoverWidth / 2 > parentBounds.width {
|
||||||
|
// Align to right
|
||||||
|
popoverX = sourceFrameInParent.maxX - popoverWidth
|
||||||
|
} else {
|
||||||
|
// Center on source view
|
||||||
|
popoverX = sourceFrameInParent.midX - popoverWidth / 2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
popoverX = max(0, min(popoverX, parentBounds.width - popoverWidth))
|
||||||
|
|
||||||
|
return (popoverX, popoverY)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user