Пользовательская проблема анимации UIViewController - PullRequest
0 голосов
/ 04 ноября 2018

Я создал простую пользовательскую анимацию перехода для UIViewController с UIViewControllerAnimatedTransitioning. Все работает, но когда появляется представление цели, контент начинает появляться из нижнего правого угла, а когда вид исчезает, контент исчезает из левого верхнего угла. Я приложил GIF с примером. Это мой код:

CustomViewAnimator.swift

class CustomViewAnimator: NSObject, UIViewControllerAnimatedTransitioning {

    private let interval = 0.5
    var forward = false
    var originFrame: CGRect = .zero

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return interval
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        let containerView = transitionContext.containerView

        guard let toView = transitionContext.view(forKey: .to) else {return}
        guard let fromView = transitionContext.view(forKey: .from) else {return}
        let destinationView = forward ? toView : fromView
        destinationView.alpha = forward ? 0 : 1

        forward ? containerView.addSubview(toView) : containerView.insertSubview(toView, belowSubview: fromView)
        forward ? (destinationView.frame = originFrame) : (destinationView.frame = fromView.frame)

        UIView.animate(withDuration: interval, animations: {

            self.forward ? (destinationView.frame = fromView.frame) : (destinationView.frame = self.originFrame)
            destinationView.alpha = self.forward ? 1 : 0

        }) { (finished) in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }

    }

}

MainViewController.self

class MainViewController: UIViewController {

    private var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        setup()
    }

    @objc private func openView() {
        let viewController = TargetViewController()
        viewController.transitioningDelegate = self
        navigationController?.pushViewController(viewController, animated: true)

    }
}

extension MainViewController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {

        let animator = CustomViewAnimator()
        animator.originFrame = button.frame
        animator.forward = (operation == .push)
        return animator
    }
}

extension MainViewController: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        let animator = CustomViewAnimator()
        animator.forward = true
        return animator
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        let animator = CustomViewAnimator()
        animator.forward = false
        return animator
    }
}

TargetViewController.swift

class TargetViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        setup()
    }

}

extension TargetViewController {

    fileprivate func setup() {
        view.backgroundColor = .orange
        navigationItem.title = "Target view"

        let label: UILabel = {
            let label = UILabel()
            label.translatesAutoresizingMaskIntoConstraints = false
            label.text = "Hello from target view :)"
            label.textColor = .white
            label.font = UIFont.boldSystemFont(ofSize: 18)
            return label
        }()
        view.addSubview(label)

        label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }

}

Кто-нибудь может сказать, как я могу решить эту проблему, чтобы ярлык (или любой другой контент) в TargetViewController оставался на своих местах?

enter image description here

Ответы [ 2 ]

0 голосов
/ 04 ноября 2018

Я согласен с обсуждением из других ответов. Мое предложение состоит в том, чтобы вместо анимации фрейма UIView, вы можете анимировать маску целевого вида следующим образом. Это должно быть результатом того, что опера действительно хочет.

Жирная часть - это отличие от оригинального сообщения.

 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

    let containerView = transitionContext.containerView

    guard let toView = transitionContext.view(forKey: .to) else {return}
    guard let fromView = transitionContext.view(forKey: .from) else {return}
    let destinationView = forward ? toView : fromView
    destinationView.alpha = forward ? 0 : 1

let maskView = UIView.init (frame: forward? OriginFrame: fromView.frame)

maskView.backgroundColor = UIColor.white

destinationView.mask = maskView

    forward ? containerView.addSubview(toView) : containerView.insertSubview(toView, belowSubview: fromView)
    forward ? (destinationView.frame = toView.frame) : (destinationView.frame = fromView.frame)


    UIView.animate(withDuration: interval, animations: {

self.forward? (destinationView.mask? .frame = fromView.frame): (destinationView.mask? .frame = self.originFrame)

        destinationView.alpha = self.forward ? 1 : 0
            }) { (finished) in

        transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
    }

}
0 голосов
/ 04 ноября 2018

В основном ваша проблема из-за смешивания Auto Layout и кадров. Вы размещаете подпредставления (кнопки и метки) в представлениях ViewController s с ограничениями, но для анимации вы используете обновления кадров. Поэтому, как я правильно понимаю, как работает макет, ваши ограничения меток не активны во время перехода или, по крайней мере, не используются механизмом макетов для вычисления позиции метки.

Итак, лучший совет - избегать покадровой анимации при переходе и пытаться создать соответствующие ограничения для .from и .to представлений и констант анимированных ограничений. Это заняло бы больше кода, но вы можете быть уверены, что вы не смешаете две разные стратегии для макета.

Более простое решение - containerView подсчитать ограничения и правильно расположить элементы во время анимации, просто добавив containerView.layoutIfNeeded() в блок анимации. Так было бы:

UIView.animate(withDuration: interval, animations: {
    self.forward ? (destinationView.frame = fromView.frame) : (destinationView.frame = self.originFrame)
    destinationView.alpha = self.forward ? 1 : 0
    containerView.layoutIfNeeded()
}) { (finished) in
    transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}

Но это только заставляет вещи работать и не решает основной проблемы при одновременном использовании двух стратегий компоновки.

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