使用 CABasicAnimation 强制连续动画
当某些属性发生更改时,我的模型中会触发一条通知。结果,特定视图对象中的选择器捕获通知以相应地更改视图的位置。
通知导致窗口上的视图沿特定方向移动(始终垂直或水平移动,并且始终以窗口上的标准步长大小移动)。用户操作可能会导致多个通知相继触发。例如,可以发送 3 个通知来将视图向下移动三级,然后可以发送另外两个通知来将视图向右移动两级。
问题是当我执行动画时,它们不会连续发生。因此,在前面的示例中,虽然我希望视图缓慢向下移动三个空格,然后由于通知而移动两个空格,但它最终会沿对角线移动到新位置。
这是我的两个选择器的代码(请注意,placePlayer 根据模型中的当前信息设置视图的位置):
- (void)moveEventHandler: (NSNotification *) notification
{
[self placePlayer];
CABasicAnimation* moveAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
moveAnimation.duration = 3;
moveAnimation.fillMode = kCAFillModeForwards; // probably not necessary
moveAnimation.removedOnCompletion = NO; // probably not necessary
[[self layer] addAnimation:moveAnimation forKey:@"animatePosition"];
}
有关如何多次调用此方法强制动画逐步执行而不是全部执行的任何建议立刻?谢谢!!
I have a notification that fires in my model when certain properties change. As a result, a selector in a particular view object catches the notifications to change the position of the view accordingly.
The notifications causes a view on the window to move in a particular direction (always vertically or horizontally and always by a standard step size on the window). It's possible for the user-actions to cause several notifications to fire one after the other. For example, 3 notifications could be sent to move the view down three steps, then two more notifications could be sent to move the view to the right two steps.
The problem is that as I execute the animations, they don't happen consecutively. So, in the previous example, though I want the view to move slowly down three spaces and then move over two spaces as a result of the notifications, instead it ends up moving diagonally to the new position.
Here is the code for my two selectors (note that placePlayer sets the position of the view according to current information in the model):
- (void)moveEventHandler: (NSNotification *) notification
{
[self placePlayer];
CABasicAnimation* moveAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
moveAnimation.duration = 3;
moveAnimation.fillMode = kCAFillModeForwards; // probably not necessary
moveAnimation.removedOnCompletion = NO; // probably not necessary
[[self layer] addAnimation:moveAnimation forKey:@"animatePosition"];
}
Any suggestions on how to make multiple calls to this methods force animation to execute step-by-step rather than all at once? Thanks!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为您可能想要在这里做的是设置一个需要连续发生的动画队列并设置动画委托,以便您将收到animationDidStop:finished:消息。这样,当一个动画完成时,您可以启动队列中的下一个动画。
I think what you might want to do here is set up a queue of animations that need to happen consecutively and set the animations delegate so that you will receive the animationDidStop:finished: message. This way when one animation is completed you can set off the next one in the queue.
我实现的解决方案确实使用了队列。这是一个相当完整的描述:
这一切都是在名为 PlayerView 的视图类中完成的。在标题中,我包含以下内容:
顺便说一句, NSMutableArray+QueueAdditions.h/m 中的 QueueAdditions 类别如下所示:
接下来,在 PlayerView 的实现中,我有以下内容:
说明:
视图从以下位置订阅适当的通知模型对象(玩家)。当它捕获通知时,它会检查是否已经在执行动画(使用 animatingPlayer 属性)。如果是这样,它会从通知中获取信息(注意玩家应该如何进行动画处理),将该信息放入字典中,并将该字典添加到动画队列中。如果当前没有动画,该方法会将 animatingPlayer 设置为 true 并调用适当的 do[Whatever]Animation 例程。
每个 do[Whatever]Animation 例程执行适当的动画,将 setAnimationDidStopSelector 设置为animationDidStop:finished:context:。当每个动画完成时,animationDidStop:finished:context: 方法(在检查是否应立即停止所有动画之后)将通过从队列中拉出下一个字典并解释其数据来执行队列中的下一个动画,以便调用适当的 do[Whatever] 动画方法。如果队列中没有动画,则该例程将 animatingPlayer 设置为 NO 并发布通知,以便其他对象可以知道播放器何时适当停止其当前的动画运行。
就是这样。可能有一个更简单的方法(?)但这对我来说效果很好。如果您有兴趣查看实际结果,请在 App Store 中查看我的 Mazin 应用程序。
谢谢。
The solution I implemented does indeed use a queue. Here's a pretty complete description:
This is all done in a view class called PlayerView. In the header I include the following:
As an aside, the QueueAdditions category in NSMutableArray+QueueAdditions.h/m looks like this:
Next, in the implementation of the PlayerView, I have the following:
Explanation:
The view subscribes to appropriate notifications from the model object (player). When it captures a notification, it checks to see if it is already doing an animation (using the animatingPlayer property). If so, it takes the information from the notification (noting how the player is supposed to be animated), puts that information into a dictionary, and adds that dictionary to the animation queue. If there is no animation currently going, the method will set animatingPlayer to true and call an appropriate do[Whatever]Animation routine.
Each do[Whatever]Animation routine performs the proper animations, setting a setAnimationDidStopSelector to animationDidStop:finished:context:. When each animation finishes, the animationDidStop:finished:context: method (after checking whether all animations should be stopped immediately) will perform the next animation in the queue by pulling the next dictionary out of the queue and interpreting its data in order to call the appropriate do[Whatever]Animation method. If there are no animations in the queue, that routine sets animatingPlayer to NO and posts a notification so other objects can know when the player has appropriately stopped its current run of animations.
That's about it. There may be a simpler method (?) but this worked pretty well for me. Check out my Mazin app in the App Store if you're interested in seeing the actual results.
Thanks.
您应该考虑在数组中沿着动画路径提供多个点,如下所示。
下面的示例指定了沿 y 轴的多个点,但您也可以指定您希望动画遵循的贝塞尔曲线路径。
基本动画和关键帧动画之间的主要区别在于关键帧允许您指定路径上的多个点。
You should think about providing multiple points along the animation path in an array as shown below.
The example below specifies multiple points along the y-axis but you can also specify a bezier path that you want your animation to follow.
The main difference between basic animation and key-frame animation is that Key-frame allows you to specify multiple points along the path.