UINavigationController navigationBar перемещается вниз после обновления ограничений макета (во всплывающем окне) - PullRequest
0 голосов
/ 01 мая 2019

Я реализую свой собственный UIPopoverController. (Вот тестовый проект, если вы хотите увидеть ошибку: https://github.com/d3mueller/PopupController-Test)

Моя версия использует child viewController, чтобы показать всплывающее окно / всплывающее окно вместо его представления.

Это работает, в основном. Тем не менее, есть одна странная ошибка, которая возникает, когда клавиатура отклоняется (когда она отображается, поповер перемещается вверх, чтобы компенсировать, а после этого он должен двигаться вниз):

Если viewController (который я хочу показать как всплывающее окно) - это UINavigationController, тогда UINavigationBar странным образом опускается при отклонении клавиатуры:

enter image description here

(голубая полоса - navigation bar)


Понятия не имею, что там происходит. Я не могу понять это. Почему он это делает?

Спасибо за любую помощь с этим:)


(Следующий код из класса Popup в моем тестовом проекте, связанном выше:)

class Popup {
    // MARK: - Properties
    // ========== PROPERTIES ==========
    private var isPresenting: Bool {
        return presentingViewController != nil && presentedViewController != nil
    }

    private weak var presentingViewController: UIViewController? = nil
    private weak var presentedViewController: UIViewController? = nil

    public var padding: CGFloat = 10
    public var size: CGSize = CGSize(width: 375, height: 1000)

    private lazy var targetLocator: UIView = {
        let targetLocator = UIView()
        targetLocator.accessibilityIdentifier = "targetLocator"
        targetLocator.isUserInteractionEnabled = false
        targetLocator.alpha = 0.8
        targetLocator.translatesAutoresizingMaskIntoConstraints = true

        return targetLocator
    }()

    private lazy var holderView: UIView = {
        let view = UIView()
        view.accessibilityIdentifier = "HolderView"
        view.backgroundColor = .gray
        view.layer.masksToBounds = true
        view.layer.cornerRadius = 10
        view.layer.zPosition = 5

        return view
    }()

    private lazy var tapRecognizerView: UIView = {
        let view = UIView()
        view.isUserInteractionEnabled = true
        view.addGestureRecognizer(self.tapGestureRecognizer)

        return view
    }()

    private var centerOffset: CGPoint = .zero

    private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
        return UITapGestureRecognizer(target: self, action: #selector(handleTap(tap:)))
    }()

    private var bottomConstraint: Constraint? = nil
    // ====================

    // MARK: - Initializers
    // ========== INITIALIZERS ==========
    init() {
        // Add Listener for keyboard
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(notification:)), name: UIWindow.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(notification:)), name: UIWindow.keyboardWillHideNotification, object: nil)
    }

    deinit {
        // Remove observers
        NotificationCenter.default.removeObserver(self)
    }
    // ====================

    // MARK: - Overrides
    // ========== OVERRIDES ==========
    // ====================


    // - TODO: Arrow an der Seite, auf targetView zeigend
    // - TODO: Comfort funktion für contentSize
    // - TODO: Auf Tastatur-Erscheinen reagieren (buggy, navigation bar verschiebt sich irgendwie)
    // - TODO: "Close" button in settings vc darf nicht dismissen!

    // MARK: - Functions
    // ========== FUNCTIONS ==========
    public func present(_ presentedVC: UIViewController, on presenting: UIViewController, target targetView: UIView) {
        guard let view = presenting.view else { return }
        self.presentingViewController = presenting
        self.presentedViewController = presentedVC

        // Add cellLocator (target view might be a cell that loses its position at some point)
        // This uses translatesAutoresizingMaskIntoConstraints to have proper constraints
        view.addSubview(targetLocator)
        targetLocator.frame = targetView.convert(targetView.bounds, to: view)

        tapRecognizerView.frame = view.frame
        tapGestureRecognizer.isEnabled = true
        view.addSubview(tapRecognizerView)
        tapRecognizerView.snp.remakeConstraints { (make) in
            make.edges.equalToSuperview()
        }

        // Add the holder view
        view.addSubview(holderView)

        // Do not use targetView.center as that use from the superview's coordinate system
        let targetViewCenter = targetView.convert(CGPoint(x: targetView.bounds.width / 2, y: targetView.bounds.height / 2), to: view)
        centerOffset = CGPoint(x: targetViewCenter.x - view.center.x, y: targetViewCenter.y - view.center.y)

        holderView.snp.remakeConstraints { (make) in
            make.leading.greaterThanOrEqualToSuperview().offset(padding)
            make.trailing.lessThanOrEqualToSuperview().offset(-padding)

            make.top.greaterThanOrEqualTo(view.safeAreaLayoutGuide.snp.top).offset(padding)
            self.bottomConstraint = make.bottom.lessThanOrEqualTo(view.safeAreaLayoutGuide.snp.bottom).offset(-padding).constraint

            make.centerY.equalTo(targetLocator).priority(750)
            make.width.equalTo(self.size.width)
            make.height.equalTo(self.size.height).priority(750)
            if centerOffset.x >= 0 {
                // left
                make.trailing.equalTo(targetLocator.snp.leading).offset(-10).priority(750)
            } else {
                // right
                make.leading.equalTo(targetLocator.snp.trailing).offset(10).priority(750)
            }
        }

        // Animate it in
        holderView.alpha = 0.0
        holderView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
        UIViewPropertyAnimator(duration: 0.3, dampingRatio: 0.8) {
            self.holderView.transform = .identity
            self.holderView.alpha = 1.0
            }.startAnimation()

        // Add child VC
        presenting.addChild(presentedVC)
        holderView.addSubview(presentedVC.view)
        presentedVC.didMove(toParent: presenting)

        presentedVC.view.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }

    }

    public func dismiss() {
        guard let presentedViewController = self.presentedViewController else { return }

        // Animate out the holderView
        let animator = UIViewPropertyAnimator(duration: 0.3, dampingRatio: 0.8) {
            self.holderView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
            self.holderView.alpha = 0.0
        }

        animator.addCompletion { (_) in

            // Remove centerOffset
            self.centerOffset = .zero

            // Remove targetLocator
            self.targetLocator.removeFromSuperview()

            // Remove tapRecognizerView
            self.tapRecognizerView.removeFromSuperview()

            // Remove child vc (that's being presented)
            presentedViewController.willMove(toParent: nil)
            presentedViewController.view.removeFromSuperview()
            presentedViewController.removeFromParent()

            // Remove holderView
            self.holderView.removeFromSuperview()
        }

        animator.startAnimation()
    }

    @objc private func handleTap(tap: UITapGestureRecognizer) {
        tapGestureRecognizer.isEnabled = false
        dismiss()
    }

    @objc private func keyboardWillShow(notification: Notification) {
        guard isPresenting else { return }

        let keyboardSize = (notification.userInfo?  [UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let keyboardHeight: CGFloat = keyboardSize?.height ?? 0

        // This simply updates the bottom constraint
        self.bottomConstraint?.update(offset: -padding - keyboardHeight)

        UIViewPropertyAnimator(duration: 2.4, dampingRatio: 0.8) {
            self.presentingViewController?.view.layoutIfNeeded()
            }.startAnimation()
    }

    @objc private func keyboardWillHide(notification: Notification) {
        guard isPresenting else { return }

        self.bottomConstraint?.update(offset: -padding)
        UIViewPropertyAnimator(duration: 2.4, dampingRatio: 0.8) {
            self.presentingViewController?.view.layoutIfNeeded()
            }.startAnimation()
    }
    // ====================


}

EDIT: Так что это не так, когда я изменяю код перехода вниз:

    @objc private func keyboardWillHide(notification: Notification) {
        guard isPresenting else { return }

        self.bottomConstraint?.update(offset: -padding)

        // New Line (This way it works but it obviously messes up the animation
        self.presentingViewController?.view.layoutIfNeeded()
        //

        UIViewPropertyAnimator(duration: 2.4, dampingRatio: 0.8) {
            self.presentingViewController?.view.layoutIfNeeded()
            }.startAnimation()
    }

Но это не очень хорошее решение

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...