diff --git a/Examples/DemosApp/DemosApp/ComponentsPreview/Helpers/ModalPreview+Helpers.swift b/Examples/DemosApp/DemosApp/ComponentsPreview/Helpers/ModalPreview+Helpers.swift index 32755715..bc195431 100644 --- a/Examples/DemosApp/DemosApp/ComponentsPreview/Helpers/ModalPreview+Helpers.swift +++ b/Examples/DemosApp/DemosApp/ComponentsPreview/Helpers/ModalPreview+Helpers.swift @@ -194,6 +194,7 @@ Enim habitant laoreet inceptos scelerisque senectus, tellus molestie ut. Eros ri HStack { Text(self.headerTitle) .font(self.headerFont.font) + Spacer() } } else { EmptyView() @@ -211,6 +212,7 @@ Enim habitant laoreet inceptos scelerisque senectus, tellus molestie ut. Eros ri } } .font(self.bodyFont.font) + .multilineTextAlignment(.leading) } static func suFooter( diff --git a/Sources/ComponentsKit/Components/Modal/SwiftUI/ModalContent.swift b/Sources/ComponentsKit/Components/Modal/SwiftUI/ModalContent.swift index df582a0b..1f379c1e 100644 --- a/Sources/ComponentsKit/Components/Modal/SwiftUI/ModalContent.swift +++ b/Sources/ComponentsKit/Components/Modal/SwiftUI/ModalContent.swift @@ -24,10 +24,7 @@ struct ModalContent: View { } var body: some View { - VStack( - alignment: .leading, - spacing: self.model.contentSpacing - ) { + VStack(spacing: self.model.contentSpacing) { self.contentHeader() .observeSize { self.headerSize = $0 diff --git a/Sources/ComponentsKit/Components/Modal/UIKit/UKBottomModalController.swift b/Sources/ComponentsKit/Components/Modal/UIKit/UKBottomModalController.swift index 6a30d47f..db5b9a10 100644 --- a/Sources/ComponentsKit/Components/Modal/UIKit/UKBottomModalController.swift +++ b/Sources/ComponentsKit/Components/Modal/UIKit/UKBottomModalController.swift @@ -95,7 +95,7 @@ public class UKBottomModalController: UKModalController { public override func layout() { super.layout() - self.contentView.bottom(self.model.outerPaddings.bottom, safeArea: true) + self.contentViewBottomConstraint = self.contentView.bottom(self.model.outerPaddings.bottom, safeArea: true).bottom } // MARK: - UIViewController Methods diff --git a/Sources/ComponentsKit/Components/Modal/UIKit/UKCenterModalController.swift b/Sources/ComponentsKit/Components/Modal/UIKit/UKCenterModalController.swift index 64a5a34e..c31e8704 100644 --- a/Sources/ComponentsKit/Components/Modal/UIKit/UKCenterModalController.swift +++ b/Sources/ComponentsKit/Components/Modal/UIKit/UKCenterModalController.swift @@ -88,11 +88,15 @@ public class UKCenterModalController: UKModalController { public override func layout() { super.layout() - self.contentView.bottomAnchor.constraint( + self.contentViewBottomConstraint = self.contentView.bottomAnchor.constraint( lessThanOrEqualTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -self.model.outerPaddings.bottom - ).isActive = true - self.contentView.centerVertically() + ) + self.contentViewBottomConstraint?.isActive = true + + let verticalConstraint = self.contentView.centerYAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerYAnchor) + verticalConstraint.isActive = true + verticalConstraint.priority = .defaultLow } // MARK: - UIViewController Methods diff --git a/Sources/ComponentsKit/Components/Modal/UIKit/UKModalController.swift b/Sources/ComponentsKit/Components/Modal/UIKit/UKModalController.swift index b0992489..51e3e238 100644 --- a/Sources/ComponentsKit/Components/Modal/UIKit/UKModalController.swift +++ b/Sources/ComponentsKit/Components/Modal/UIKit/UKModalController.swift @@ -15,6 +15,7 @@ open class UKModalController: UIViewController { public let model: VM private var contentViewWidthConstraint: NSLayoutConstraint? + var contentViewBottomConstraint: NSLayoutConstraint? // MARK: - Subviews @@ -53,6 +54,12 @@ open class UKModalController: UIViewController { fatalError("init(coder:) has not been implemented") } + // MARK: Deinitialization + + deinit { + NotificationCenter.default.removeObserver(self) + } + // MARK: - Lifecycle open override func viewDidLoad() { @@ -65,7 +72,7 @@ open class UKModalController: UIViewController { // MARK: - Setup - /// Sets up the modal's subviews and gesture recognizers. + /// Sets up the modal's subviews, gesture recognizers and observers. open func setup() { self.view.addSubview(self.overlay) self.view.addSubview(self.contentView) @@ -89,6 +96,20 @@ open class UKModalController: UIViewController { controller.handleTraitChanges() } } + + NotificationCenter.default.addObserver( + self, + selector: #selector(self.handleKeyboardWillShow), + name: UIResponder.keyboardWillShowNotification, + object: nil + ) + + NotificationCenter.default.addObserver( + self, + selector: #selector(self.handleKeyboardWillHide), + name: UIResponder.keyboardWillHideNotification, + object: nil + ) } @objc func handleOverlayTap() { @@ -96,6 +117,24 @@ open class UKModalController: UIViewController { self.dismiss(animated: true) } + @objc func handleKeyboardWillShow(notification: NSNotification) { + if let keyboardHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height { + let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? CGFloat ?? 0.25 + UIView.animate(withDuration: duration) { + self.contentViewBottomConstraint?.constant = -keyboardHeight - self.model.contentPaddings.bottom + self.view.safeAreaInsets.bottom + self.view.layoutIfNeeded() + } + } + } + + @objc func handleKeyboardWillHide(notification: NSNotification) { + let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? CGFloat ?? 0.25 + UIView.animate(withDuration: duration) { + self.contentViewBottomConstraint?.constant = -self.model.contentPaddings.bottom + self.view.layoutIfNeeded() + } + } + // MARK: - Style /// Applies styling to the modal's subviews.