首页 > 解决方案 > 导航视图将全屏转换为具有角半径的视图

问题描述

我正在尝试从启动画面创建应用程序主屏幕动画,例如在启动屏幕完成(全)屏幕颜色转换为应用程序徽标背景颜色后。目前低于我所期望的代码类型的存档。但是,这种转换CAShapeLayer与圆角半径无关。如果没有圆角半径,它可以正常工作,当我尝试使用圆形/椭圆形/圆角半径动画时,它看起来像下面的 gif。

尝试了一些其他 StackOverflow 答案,这些答案创建了那些不起作用的圆形动画。这是其中之一

    weak var viewTransitionContext: UIViewControllerContextTransitioning!

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        viewTransitionContext = transitionContext

        guard let fromVC = viewTransitionContext.viewController(forKey: .from) else { return }
        guard let toVC = viewTransitionContext.viewController(forKey: .to) else { return }

        if fromVC.isKind(of: SOGSplashViewController.self) && toVC.isKind(of: SOGHomeViewController.self) {
            guard let toVCView = transitionContext.view(forKey: .to) else { return }
            guard let fromVCView = transitionContext.view(forKey: .from) else { return }

            let containerView = transitionContext.containerView
            let labelWidth = UIDevice.width() * 0.75
            let labelHeight = labelWidth * 0.7
            let xAxis = (UIDevice.width() - labelWidth)/2.0
            let yAxis = ((UIDevice.height()/2.0) - labelHeight)/2.0
            let labelRect = CGRect(x: xAxis, y: yAxis, width: labelWidth, height: labelHeight)
            let radius = (UIDevice.height()/2.0)*0.1
            let fromFrame = fromVCView.bounds
            let animationTime = transitionDuration(using: transitionContext)

            let maskLayer = CAShapeLayer()
            maskLayer.isOpaque = false
            maskLayer.fillColor = fromVCView.backgroundColor?.cgColor
            maskLayer.backgroundColor = UIColor.clear.cgColor
            maskLayer.path = toPathValue.cgPath

            let maskAnimationLayer = CABasicAnimation(keyPath: "path")
            maskAnimationLayer.fromValue = (UIBezierPath(rect: fromFrame)).cgPath
            maskAnimationLayer.toValue = toPathValue.cgPath
            maskAnimationLayer.duration = animationTime
            maskAnimationLayer.delegate = self as? CAAnimationDelegate

            containerView.addSubview(fromVCView)
            containerView.addSubview(toVCView)
            fromVCView.layer.add(maskAnimationLayer, forKey: nil)
            maskLayer.add(maskAnimationLayer, forKey: "path")
            containerView.layer.addSublayer(maskLayer)

            let deadLineTime = DispatchTime.now() + .seconds(1)
            DispatchQueue.main.asyncAfter(deadline: deadLineTime) {
                UIView.animate(withDuration: 0.2, animations: {
                    maskLayer.opacity = 0
                }, completion: { (isSuccess) in
                    self.viewTransitionContext.completeTransition(true)
                })
            }
        }
    }

在此处输入图像描述

标签: swiftnavigationuibezierpathcashapelayercaanimation

解决方案


如果您通过 Core Animation 之类的通用方式将矩形路径转换为圆角矩形路径是一个非常复杂的操作。您最好使用其cornerRadius属性CALayer是可动画的。

这是一个基于约束的动画的工作示例:

class ViewController: UIViewController {
    @IBOutlet var constraints: [NSLayoutConstraint]!
    @IBOutlet var contentView: UIView!

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

    override func viewDidAppear(_ animated: Bool) {
        self.contentView.layer.cornerRadius = 10.0
        self.animate(nil)
    }

    @IBAction func animate(_ sender: Any?) {
        for c in constraints {
            c.constant = 40.0
        }
        UIView.animate(withDuration: 4.0) {
            self.view.layoutIfNeeded()
            self.contentView.layer.cornerRadius = 40.0
        }
    }
}

contentView指向应该动画的内部视图,并constraints参考定义从视图控制器的视图到内容视图的距离的四个布局约束。

例子

这只是一个简单粗略的例子,当然可以改进。


推荐阅读