0

I hope to create a specific custom transition animation for a button that grows in size
to fill center of the screen overlaying the previous ViewController.
luckily I've even found how I want it to look like! (Reference))

I'm new to coding so I know this is something I shouldn't get into, but I wanted to give it a go
and unlike in the reference, I planned to put just one textField & a button inside -

but it seems like I've been digging the wrong hole.
The overall animation doesn't look great either with the background visible (even with .clear)
to add on, I played around with much of the numbers...
here's a gif of what I made (Test Animation)

Is there any way to salvage pieces of my code to recreate like the one in the reference?
and if it's not view (from my today's experience...) what would be a way to create it?


here's what I've done so far

---- Presenter ----

class Presenter: NSObject, UIViewControllerTransitioningDelegate {

    private let transition = Transition()

    func present(_ viewController: UIViewController, from parent: UIViewController) {
        viewController.modalPresentationStyle = .overFullScreen
        viewController.transitioningDelegate = self
        parent.present(viewController, animated: true)
    }

    func animationController(forPresented presented: UIViewController,
                             presenting: UIViewController,
                             source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        transition.direction = .present
        return transition
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        transition.direction = .dismiss
        return transition
    }
}

---- Transition ----

class Transition: NSObject, UIViewControllerAnimatedTransitioning {

    enum Direction {
        case present
        case dismiss
    }
    
    var direction: Direction = .present
    private var presentedConstraints: [NSLayoutConstraint] = []
    private var dismissedConstraints: [NSLayoutConstraint] = []

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 0.7 }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        switch direction {
        case .present:
            present(using: transitionContext)
        case .dismiss:
            dismiss(using: transitionContext)
        }
    }

    private func present(using context: UIViewControllerContextTransitioning) {
        guard let presentedView = context.view(forKey: .to) else {
            context.completeTransition(false)
            return
        }

        context.containerView.addSubview(presentedView)
        presentedView.translatesAutoresizingMaskIntoConstraints = false

        presentedConstraints = [
            presentedView.leftAnchor.constraint(equalTo: context.containerView.leftAnchor, constant: 10),
            presentedView.rightAnchor.constraint(equalTo: context.containerView.rightAnchor, constant: -10),
            presentedView.topAnchor.constraint(equalTo: context.containerView.topAnchor),
            presentedView.bottomAnchor.constraint(equalTo: context.containerView.centerYAnchor, constant: 170)
        ]

        dismissedConstraints = [
            presentedView.leftAnchor.constraint(equalTo: context.containerView.leftAnchor, constant: 80),
            presentedView.rightAnchor.constraint(equalTo: context.containerView.rightAnchor, constant: -80),
            presentedView.topAnchor.constraint(equalTo: context.containerView.topAnchor, constant: 400),
            presentedView.bottomAnchor.constraint(equalTo: context.containerView.bottomAnchor, constant: -30)
        ]

        NSLayoutConstraint.activate(dismissedConstraints)

        context.containerView.setNeedsLayout()
        context.containerView.layoutIfNeeded()

        NSLayoutConstraint.deactivate(dismissedConstraints)
        NSLayoutConstraint.activate(presentedConstraints)


        UIView.animate(
            withDuration: transitionDuration(using: context),
            delay: 0,
            usingSpringWithDamping: 0.8,
            initialSpringVelocity: 0,
            options: .curveEaseInOut,
            animations: {
                context.containerView.setNeedsLayout()
                context.containerView.layoutIfNeeded()
            },
            completion: { _ in
                context.completeTransition(true)
            })
    }

    private func dismiss(using context: UIViewControllerContextTransitioning) {
        NSLayoutConstraint.deactivate(presentedConstraints)
        NSLayoutConstraint.activate(dismissedConstraints)

        UIView.animate(
            withDuration: transitionDuration(using: context),
            delay: 0,
            usingSpringWithDamping: 0.8,
            initialSpringVelocity: 0,
            options: .curveEaseInOut,
            animations: {
                context.containerView.setNeedsLayout()
                context.containerView.layoutIfNeeded()
            },
            completion: { _ in
                context.completeTransition(true)
            })
    }
}

and finally just the 2nd VC that has the view!

---- 2nd VC ----


protocol MessageViewControllerDelegate: AnyObject {
    func messageViewController(_ vc: MessageViewController, didSaveTodo: Todo)
}

class MessageViewController: UIViewController {
    
    weak var delegate: MessageViewControllerDelegate?
    var todo: Todo?

    let messageView = UIView()
    let sendButton = UIButton()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        
        view.addSubview(messageView)
        view.addSubview(sendButton)
        
        sendButton.translatesAutoresizingMaskIntoConstraints = false
        sendButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        sendButton.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 50).isActive = true
        sendButton.backgroundColor = .blue
        sendButton.addTarget(self, action: #selector(save), for: .touchUpInside)
    }
    
    override func viewDidLayoutSubviews() {
        messageView.backgroundColor = .yellow
        messageView.layer.cornerRadius = 180/2
        messageView.clipsToBounds = true
        messageView.translatesAutoresizingMaskIntoConstraints = false
        messageView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        messageView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        messageView.topAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        messageView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }

    @objc func save(_ sender: UIButton) {
        print("Save was tapped.")
        dismiss(animated: true)
    }
}
Kor_Dev
  • 1
  • 1

0 Answers0