Ios 更改viewController时保持动画

Ios 更改viewController时保持动画,ios,swift,animation,swift3,uiviewcontroller,Ios,Swift,Animation,Swift3,Uiviewcontroller,我试图在配置文件图片后面编写一个动画,以鼓励用户点击它。 这是一个越来越大越来越小的圆圈 override func layoutSubviews() { super.layoutSubviews() UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: { self.bouncedView.transform = CGAffineTransform

我试图在配置文件图片后面编写一个
动画
,以鼓励用户点击它。 这是一个越来越大越来越小的圆圈

override func layoutSubviews() {
  super.layoutSubviews()

  UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {

     self.bouncedView.transform = CGAffineTransform(scaleX:
        1.3, y: 1.3)

      }, completion: nil)

}


问题是,当我转到另一个
viewController
时,动画停止,圆圈保持在屏幕快照上的状态。你知道我怎样才能避免这个问题吗?

嗯,我还没有一个令人满意的答案(至少这会让我满意),但我想至少补充一些我通过一点实验能够得到的见解

首先,当
viewController
当前未显示时,动画似乎结束了。在您的情况下,这意味着动画将停止并以视图大1.3倍的状态结束,并停止重复<代码>布局子视图仅在第一次显示时才会被调用。至少
viewController.viewdilayoutsubviews
仅在开始时调用,而不是在返回时调用(因此视图重新出现时将不会执行
layoutSubviews
),因此动画不会重新启动

我试图将动画移动到
UIViewController
viewdide
——这也不起作用,因为停止动画会导致视图已缩放1.3倍的状态。在创建动画之前,将状态重置为
CGAffineTransform.identity

正如我所说的,这可以作为一个解决办法,帮助您解决如何让它工作的问题,但是,我认为您真正需要的是一个钩子,它可以告诉您的视图(而不是viewController)它再次出现。但下面这个简单的例子至少可以帮助其他人看一看,而不是从头开始

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {

    let animator = UIViewPropertyAnimator(duration: 1, timingParameters: UICubicTimingParameters(animationCurve: .linear))

    init(title: String) {
        super.init(nibName: nil, bundle: nil)
        self.title = title
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    let animatableView = UIView()

    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        animatableView.frame = CGRect(x: 150, y: 400, width: 100, height: 100)
        animatableView.backgroundColor = UIColor.magenta
        view.addSubview(animatableView)

        self.view = view
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        self.animatableView.transform = CGAffineTransform.identity
        UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {
            self.animatableView.transform = CGAffineTransform(scaleX:
                1.3, y: 1.3)
        }, completion: nil)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        print("\(self.title) >> Lay out")
    }
}

let tabBar = UITabBarController()
tabBar.viewControllers = [MyViewController(title: "first"), MyViewController(title: "second"), MyViewController(title: "third")]
tabBar.selectedIndex = 0
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = tabBar
编辑

我添加了几行代码来检查self.animatableView.layer.animationKeys()是否包含任何动画,切换选项卡似乎会将动画从视图的层中移除,因此每次视图重新出现时,您都必须找到添加动画的方法

编辑2
因此,我会使用@SWAT的答案,并使用
willMove(toWindow:)
而不是
布局子视图

嗯,我还没有一个令人满意的答案(至少这会让我满意),但我想至少添加一些我能够通过一点实验获得的见解

首先,当
viewController
当前未显示时,动画似乎结束了。在您的情况下,这意味着动画将停止并以视图大1.3倍的状态结束,并停止重复<代码>布局子视图仅在第一次显示时才会被调用。至少
viewController.viewdilayoutsubviews
仅在开始时调用,而不是在返回时调用(因此视图重新出现时将不会执行
layoutSubviews
),因此动画不会重新启动

我试图将动画移动到
UIViewController
viewdide
——这也不起作用,因为停止动画会导致视图已缩放1.3倍的状态。在创建动画之前,将状态重置为
CGAffineTransform.identity

正如我所说的,这可以作为一个解决办法,帮助您解决如何让它工作的问题,但是,我认为您真正需要的是一个钩子,它可以告诉您的视图(而不是viewController)它再次出现。但下面这个简单的例子至少可以帮助其他人看一看,而不是从头开始

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {

    let animator = UIViewPropertyAnimator(duration: 1, timingParameters: UICubicTimingParameters(animationCurve: .linear))

    init(title: String) {
        super.init(nibName: nil, bundle: nil)
        self.title = title
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    let animatableView = UIView()

    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        animatableView.frame = CGRect(x: 150, y: 400, width: 100, height: 100)
        animatableView.backgroundColor = UIColor.magenta
        view.addSubview(animatableView)

        self.view = view
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        self.animatableView.transform = CGAffineTransform.identity
        UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {
            self.animatableView.transform = CGAffineTransform(scaleX:
                1.3, y: 1.3)
        }, completion: nil)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        print("\(self.title) >> Lay out")
    }
}

let tabBar = UITabBarController()
tabBar.viewControllers = [MyViewController(title: "first"), MyViewController(title: "second"), MyViewController(title: "third")]
tabBar.selectedIndex = 0
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = tabBar
编辑

我添加了几行代码来检查self.animatableView.layer.animationKeys()是否包含任何动画,切换选项卡似乎会将动画从视图的层中移除,因此每次视图重新出现时,您都必须找到添加动画的方法

编辑2
因此,我会使用@SWAT的答案,使用
willMove(toWindow:)
而不是
layoutSubviews

进行转换。视图上的标识已出现。类似于以下代码的内容:

class HomeController: UIViewController {

@IBOutlet weak var viewToAnimate: UIView!
override func viewDidLoad() {
    super.viewDidLoad()
}

override func viewWillAppear(_ animated: Bool) {
    self.viewToAnimate.transform = .identity
    animateView()
}

func animateView(){
    UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {

        self.viewToAnimate.transform = CGAffineTransform(scaleX:
            1.3, y: 1.3)

    }, completion: nil)
}
}

您可能已经猜到的问题是,UIView.animate仅在ViewDidLoad方法上调用,并且由于我们在从另一个ViewController返回此ViewController时没有访问该代码的权限,因此最好在ViewWillAspect方法中启动动画

如果在选项卡之间切换时出现相同问题,请为要设置动画的视图创建一个单独的UIView子类,并按以下步骤进行操作:

class AnimateView: UIView {

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

override func willMove(toWindow newWindow: UIWindow?) {
    super.willMove(toWindow: newWindow)
    self.transform = .identity
    animateView()
}

func animateView(){
    UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {

        self.transform = CGAffineTransform(scaleX:
            1.3, y: 1.3)

    }, completion: nil)
}
}


在这里,您已将动画功能应用于UIView对象,并且每当视图出现时,动画都将被重置。

对ViewDidDisplay上的.identity进行转换。类似于以下代码的内容:

class HomeController: UIViewController {

@IBOutlet weak var viewToAnimate: UIView!
override func viewDidLoad() {
    super.viewDidLoad()
}

override func viewWillAppear(_ animated: Bool) {
    self.viewToAnimate.transform = .identity
    animateView()
}

func animateView(){
    UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {

        self.viewToAnimate.transform = CGAffineTransform(scaleX:
            1.3, y: 1.3)

    }, completion: nil)
}
}

您可能已经猜到的问题是,UIView.animate仅在ViewDidLoad方法上调用,并且由于我们在从另一个ViewController返回此ViewController时没有访问该代码的权限,因此最好在ViewWillAspect方法中启动动画

如果在选项卡之间切换时出现相同问题,请为要设置动画的视图创建一个单独的UIView子类,并按以下步骤进行操作:

class AnimateView: UIView {

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

override func willMove(toWindow newWindow: UIWindow?) {
    super.willMove(toWindow: newWindow)
    self.transform = .identity
    animateView()
}

func animateView(){
    UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {

        self.transform = CGAffineTransform(scaleX:
            1.3, y: 1.3)

    }, completion: nil)
}
}


在这里,您已将动画功能应用于UIView对象,并且每当视图出现时,动画都将重置。

您所说的“当我更改
视图控制器时”
是什么意思?如果您正在某个地方进行编辑,您是否会在此基础上提供其他UIViewController,或者是什么原因导致动画停止?最好也包括代码抱歉,它不是很清楚。。。我的意思是,例如,当我更改选项卡时,或者当我转到另一个viewControllerOK时,因此当您将选项卡更改为另一个viewControllerOK时,动画会在其所在位置暂停