Я следовал этому ответу, но использовал привязки для своего макета. Сам переход хороший, проблема в том, что когда происходит анимация и вид появляется на экране, нет отскока как на гифке из ссылки. Моя анимация просто «появляется» снизу, а не переходит снизу. Это очень внезапно, а не плавно.
Вместо использования UIView.Animate...
, как в моем коде ниже, я также попробовал animate(withDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)
, но все еще не отскакивал.
Я пробовал разные комбинации containerView.setNeedsUpdateConstraints()
, containerView.layoutIfNeeded()
, view.layoutIfNeeded()
в завершенииHandler, но нада. Играл с withDuration:
от 0.4 до 2.5 но такое же внезапное появление происходит
Сам фактический переход работает нормально, так что мне там хорошо, просто нет эффекта отскока, когда он появляется.
class ViewController: UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .custom
transitioningDelegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var bgView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = UIColor.black.withAlphaComponent(0.7)
return v
}()
let anotherVC = AnotherController()
var isPresenting = false
let fullScreenHeight = UIScreen.main.bounds.height
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
configureAnchors()
let navVC = UINavigationController(rootViewController: anotherVC)
addChildVCToParent(vc: navVC)
}
func addChildVCToParent(vc: UIViewController) {
if (!vc.view.isDescendant(of: self.view)) {
addChild(vc)
vc.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(vc.view)
vc.didMove(toParent: self)
vc.view.topAnchor.constraint(equalTo: bgView.bottomAnchor).isActive = true
vc.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
vc.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
vc.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
}
var bgViewHeightAnchor: NSLayoutConstraint?
func configureAnchors() {
view.addSubview(bgView)
bgView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
bgView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
bgView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
setBgViewHeightAnchorToFullScreenHeightAndAlphaToZero()
}
func setBgViewHeightAnchorToFullScreenHeightAndAlphaToZero() {
bgView.alpha = 0
bgViewHeightAnchor?.isActive = false
bgViewHeightAnchor = bgView.heightAnchor.constraint(equalToConstant: fullScreenHeight)
bgViewHeightAnchor?.isActive = true
}
func setBgHeightAnchorToOneFifthScreenHeightAndAlphaToOne() {
bgView.alpha = 1
bgViewHeightAnchor?.isActive = false
bgViewHeightAnchor = bgView.heightAnchor.constraint(equalToConstant: fullScreenHeight / 5)
bgViewHeightAnchor?.isActive = true
}
}
extension ViewController: UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 1
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
guard let toVC = toViewController else { return }
isPresenting = !isPresenting
if isPresenting {
containerView.addSubview(toVC.view)
setBgViewHeightAnchorToFullScreenHeightAndAlphaToZero()
// containerView.setNeedsUpdateConstraints()
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {
self.setBgViewHeightAnchorToOneFifthScreenHeightAndAlphaToOne()
// containerView.layoutIfNeeded() // using this here ruins the entire animation
// self.view.layoutIfNeeded()
}, completion: { (finished) in
// containerView.layoutIfNeeded()
// self.view.layoutIfNeeded()
transitionContext.completeTransition(true)
})
} else {
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseOut], animations: {
self.setBgViewHeightAnchorToFullScreenHeightAndAlphaToZero()
}, completion: { (finished) in
transitionContext.completeTransition(true)
})
}
}
}