なんとかするから、なんとかなる

エンジニア関係のことを書きます

iOS UIView transform doesn't scale propery while transition animetion.

Sorry for my poor English skill.

Introduction

This article shows how to solve the problem that UIView transform doesn't scale correctly while transition animation.

Transition animation make an app interactively.

But, sometimes it meka developer annoyed.

When I tried to animate a UIView scaling up and down while transition, it was not working corretly.

Conclusion

UIView transform needs to set the .identify in the completion, when it was changed in UIView animate method in transition method.

Detail

When I tried to the code below, the problem was occurred.

  1. When new UIViewcontroller was pushed to UINavigationController, a current UIView will be scaled down while transition animation is working.

  2. When new UIViewController was poped from UINavigationConroller, a curren UIView will be scaled up while transiotion aniomatio is working

PushAnimation

class PushModalAnimation: NSObject, UIViewControllerAnimatedTransitioning {
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 1.0
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toViewController = transitionContext.viewController(forKey: .to),
            let fromViewController = transitionContext.viewController(forKey: .from) else {
                transitionContext.completeTransition(true)
                return
        }
        
        transitionContext.containerView.addSubview(toViewController.view)
        transitionContext.containerView.addSubview(fromViewController.view)
        
        UIView.animate(withDuration: 1.0, delay: 0, options: [], animations: {
            fromViewController.view.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
        }) { (_) in
            transitionContext.completeTransition(true)
        }
    }
}

PopAnimation

class PopModalAnimation: NSObject, UIViewControllerAnimatedTransitioning {
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 1.0
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toViewController = transitionContext.viewController(forKey: .to),
            let fromViewController = transitionContext.viewController(forKey: .from) else {
                transitionContext.completeTransition(true)
                return
        }
        
        transitionContext.containerView.addSubview(fromViewController.view)
        transitionContext.containerView.addSubview(toViewController.view)
        
        UIView.animate(withDuration: 1.0, delay: 0, options: [], animations: {
            toViewController.view.transform = CGAffineTransform.identity
        }) { (_) in
            transitionContext.completeTransition(true)
        }
    }
}

Result

Before Push new UIViewController

f:id:hopita:20180818152404p:plain:h200

After Push new UIViewController

f:id:hopita:20180818152417p:plain:h200

After Pop new UIViewController

f:id:hopita:20180818152425p:plain:h200

After pop new UIViewController, the red UIView was bigger than its size (Befor Push new UIViewController).

Additionally, after showing this weird UIView size, tap the Home Button and came back the app. The UIView showed correctly..

How to solve the problem

After scaling down the animation in push transition, view transform need to reset the propery as .identify. Then it worked correctly.

For the solution, Before scaling down in pop transtiion, view transfrom need to set the size which was set in push transition.

The working code is below(This is part of the method.).

PushAnimation

        UIView.animate(withDuration: 1.0, delay: 0, options: [], animations: {
            fromViewController.view.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
        }) { (_) in
            fromViewController.view.transform = CGAffineTransform.identity // Need to reset the original size
            transitionContext.completeTransition(true)
        }

PopAnimation

        toViewController.view.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)// Need to set the size which was scale up from.
        UIView.animate(withDuration: 1.0, delay: 0, options: [], animations: {
            toViewController.view.transform = CGAffineTransform.identity
        }) { (_) in
            transitionContext.completeTransition(true)
        }

Finally

Though this problem was aimed at transform scale,I think this problem would be occurred in rotate and transition too.

But, when I change the UIView alpha proroperty in UIView animate method. It doesn't need to reset the property in completion handler.