【问题标题】:Swift - when or how to implement animations on view start?Swift - 何时或如何在视图开始时实现动画?
【发布时间】:2015-04-28 05:01:35
【问题描述】:

我是 Swift 新手,我正在尝试实现一个简单的游戏。在这个游戏中,一旦视图被加载,我希望周期性的动画发生。

问题是我尝试使用例如button.frame.origin.x += 50 为我的按钮设置动画,但不是将其从原点移动到右侧 50px,而是出现在 button.frame.origin.x - 50 并转到其(初始位置。 有趣的是,有一次我向用户显示了一个AlertDialog,在它显示之后,动画开始按我的预期发生。

我的问题与this topic 相同,但接受的答案并没有为我解决。

有什么想法吗?

编辑: 深入研究代码并进行大量测试,我发现显示 AlertDialog 的方法也恰好使我的计时器无效。我有两个计时器:一个用于更新 UI 时间(一个 TextField),另一个用于执行动画。两者都在安排任务。从I read here 来看,不可能有两个这样的计时器。

一个计时器对象一次只能在一个运行循环中注册, 虽然它可以添加到该运行中的多个运行循环模式 循环。

因此,显而易见的解决方案是将两个选择器(函数)合并为一个,以便计时器对这两个任务都有效。但是,如果我尝试更新 UI 并执行动画,动画将不再按预期工作。我只是迷失在这个问题上,无法让这两件事都发挥作用。

这些是我的重要代码:

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

    resetOrCreateGame()
}

func resetOrCreateGame() {
    // Do stuff to initialize values
    timerToRotate = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: "rotateBlocks", userInfo: nil, repeats: true)
}

func rotateBlocks() {
    // Calculate positions to rotate
    UIView.animateWithDuration(0.5, delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
        // Try to update a timer in the UI
        //self.timeLeft.text = String(self.seconds)

        for i in 0 ... 8 {
            println("\(i) before \(self.buttons[i].frame.origin.x) \(self.buttons[i].frame.origin.y)")
            self.buttons[i].frame.origin.x = self.positions[self.indicesToRotate[i]].x
            self.buttons[i].frame.origin.y = self.positions[self.indicesToRotate[i]].y

            println("\(i) after \(self.buttons[i].frame.origin.x) \(self.buttons[i].frame.origin.y)")
        }
        }, completion: { _ in
                println("completed")
            })

如果我留下self.timeLeft.text = String(self.seconds) 的评论,动画效果很好。无论我如何尝试更新 timeLeft,如果我这样做,它会破坏我的动画。我试图在一个单独的线程中更新它,将它分派到主线程,甚至在动画闭包中更新它:它只是不起作用。

【问题讨论】:

  • 您可以在您的应用程序中使用许多计时器。没事儿。您展示的描述谈到了一个计时器以及如何一次将其添加到一个运行循环中。
  • 问题似乎是线程更新 UI,或类似的东西。即使只使用一个计时器,它仍然不起作用。请看我添加的代码

标签: ios swift animation


【解决方案1】:

尝试使用SKActions 制作动画。

设置一个SKAction,然后在你想要动画的SpriteKit node上(将“node”替换为节点的名称),并将其命名为action

然后,调用简单方法:

[node runAction:action];

例如,如果您想设置 SKAction 以在 3 秒的时间跨度内将标题为 button 的节点向右移动 50 像素...

SKAction *action = [SKAction moveByX:50.0 y:0.0 duration:3.0];
[button runAction:action];

哎呀,如果我不多次执行某个操作,我会这样做:

[button runAction:[SKAction moveByX:50.0 y:0.0 duration:3.0]];

最后,您可以使用runAction:completion: 方法不仅运行您的SKAction,还可以在它完成后调用Objective-C block,就像在这个编码示例中一样:

SKAction *action = [SKAction moveByX:50.0 y:0.0 duration:3.0];
[button runAction:action completion:^{
     // some code here that runs after an animation completes
}];

并且,如果您想在节点上运行 序列 操作,为了不使您的代码复杂化(在 3 秒内将一个名为 button 的按钮向右移动 50 像素,然后将其淡出超过 1 秒),您可以将一系列动作编程为一个动作,如下所示:

SKAction *firstAction = [SKAction moveByX:50.0 y:0.0 duration:3.0];
SKAction *secondAction = [SKAction fadeAlphaTo:0.0 duration:1.0];
SKAction *theSequence = [SKAction sequence:[NSArray arrayWithObjects:firstAction, secondAction, nil];
[button runAction:theSequence]

您可以在 completion 块中运行另一个操作,但使用 sequence 的方法会清理代码。

【讨论】:

  • 等一下……我的答案在 Objective-C 中。你可以使用 Swift 的等价物。
  • 嗯,谢谢你的例子。但是我想执行一个非常简单的动画,我想我已经在做一个非常简单的解决方案。
  • 我会为 SpriteKit 动画使用 SKAction 并让它处理它。尝试阅读它的文档!
【解决方案2】:

终于,我找到了解决方案! 出于某种原因,问题是自动布局。禁用它后,一切都按预期工作。

希望它对未来的人有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-20
    • 1970-01-01
    • 2018-01-14
    • 1970-01-01
    • 2012-05-11
    • 2021-11-17
    • 2021-02-04
    相关资源
    最近更新 更多