Ios 自定义UIViewController动画问题

Ios 自定义UIViewController动画问题,ios,swift,animation,uiviewcontroller,Ios,Swift,Animation,Uiviewcontroller,我使用UIViewControllerAnimatedTransitioning为UIViewController创建了一个简单的自定义转换动画。一切正常,但当目标视图出现时,内容从右下角开始显示,当视图消失时,内容从左上角消失。我附上了gif的例子。这是我的代码: CustomViewAnimator.swift class CustomViewAnimator: NSObject, UIViewControllerAnimatedTransitioning { private le

我使用
UIViewControllerAnimatedTransitioning
UIViewController
创建了一个简单的自定义转换动画。一切正常,但当目标视图出现时,内容从右下角开始显示,当视图消失时,内容从左上角消失。我附上了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中的标签(或任何其他内容)固定在它们的位置上


基本上,您的问题是因为混合了自动布局和框架。在带有约束的
ViewController
s视图中定位子视图(按钮和标签),但对于动画,使用帧更新。所以,正如我正确理解布局是如何工作的一样,标签约束在转换过程中并没有激活,或者至少布局引擎并没有使用它来计算标签的位置

因此,最好的建议是避免在转换中使用帧动画,并尝试为
.from
.to
视图创建适当的约束,并为约束的常量设置动画。这将需要更多的代码,但您可以确保不会混合两种不同的布局策略

更简单的解决方案是告诉
containerView
计算约束,并在动画期间通过简单地将
containerView.layoutifneedd()
添加到动画块来适当定位元素。因此,这将是:

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)
}

但这只会让事情顺利进行,并不能解决同时使用两种布局策略的主要问题。

我同意其他答案中的讨论。我的建议是,不要设置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
让maskView=UIView.init(帧:前进?原始帧:fromView.frame) maskView.backgroundColor=UIColor.white destinationView.mask=maskView 自我推进?(destinationView.mask?frame=fromView.frame):(destinationView.mask?frame=self.originFrame)
你能展示TargetViewController,特别是它对标签的约束吗?@PeterTretyakov我通过添加TargetViewController编辑了我的帖子,我在另一个资源中发现了这一点。我用cabasicanition而不是UIView.animation修复了它
    forward ? containerView.addSubview(toView) : containerView.insertSubview(toView, belowSubview: fromView)
    forward ? (destinationView.frame = toView.frame) : (destinationView.frame = fromView.frame)


    UIView.animate(withDuration: interval, animations: {
        destinationView.alpha = self.forward ? 1 : 0
            }) { (finished) in

        transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
    }

}