使用核心动画的 NSView 显式动画

发布于 2024-11-08 01:49:03 字数 1203 浏览 4 评论 0原文

我正在尝试使用核心动画在 NSView 中滑动。我认为我需要使用显式动画,而不是依赖于诸如 [[view animator] setFrame:newFrame] 之类的东西。这主要是因为我需要设置动画委托以便在动画完成后采取行动。

我使用动画师让它工作得很好,但正如我所说,动画完成时我需要收到通知。我的代码目前看起来像:

// Animate the controlView
NSRect viewRect = [controlView frame];
NSPoint startingPoint = viewRect.origin;
NSPoint endingPoint = startingPoint;
endingPoint.x += viewRect.size.width;
[[controlView layer] setPosition:NSPointToCGPoint(endingPoint)];

CABasicAnimation *controlPosAnim = [CABasicAnimation animationWithKeyPath:@"position"];
[controlPosAnim setFromValue:[NSValue valueWithPoint:startingPoint]];
[controlPosAnim setToValue:[NSValue valueWithPoint:endingPoint]];
[controlPosAnim setDelegate:self];
[[controlView layer] addAnimation:controlPosAnim forKey:@"controlViewPosition"];

这在视觉上可行(并且我在最后得到通知),但看起来实际的 controlView 没有移动。如果我刷新窗口,controlView 就会消失。我尝试替换

[[controlView layer] setPosition:NSPointToCGPoint(endingPoint)];

[controlView setFrame:newFrame];

,这确实会导致视图(和图层)移动,但它正在破坏某些东西,以至于我的应用程序很快就会因段错误而死亡。

大多数显式动画的示例似乎只是移动CALayer。必须有一种方法可以移动 NSView 并且能够设置委托。任何帮助将不胜感激。

I'm trying to slide in a NSView using core animation. I think I need to use explicit animation rather than relying on something like [[view animator] setFrame:newFrame]. This is mainly because I need to set the animation delegate in order to take action after the animation is finished.

I have it working just fine using the animator, but as I said, I need to be notified when the animation finishes. My code currently looks like:

// Animate the controlView
NSRect viewRect = [controlView frame];
NSPoint startingPoint = viewRect.origin;
NSPoint endingPoint = startingPoint;
endingPoint.x += viewRect.size.width;
[[controlView layer] setPosition:NSPointToCGPoint(endingPoint)];

CABasicAnimation *controlPosAnim = [CABasicAnimation animationWithKeyPath:@"position"];
[controlPosAnim setFromValue:[NSValue valueWithPoint:startingPoint]];
[controlPosAnim setToValue:[NSValue valueWithPoint:endingPoint]];
[controlPosAnim setDelegate:self];
[[controlView layer] addAnimation:controlPosAnim forKey:@"controlViewPosition"];

This visually works (and I get notified at the end) but it looks like the actual controlView doesn't get moved. If I cause the window to refresh, the controlView disappears. I tried replacing

[[controlView layer] setPosition:NSPointToCGPoint(endingPoint)];

with

[controlView setFrame:newFrame];

and that does cause the view (and layer) to move, but it is corrupting something such that my app dies with a seg fault soon afterwards.

Most of the examples of explicit animation seem to only be moving a CALayer. There must be a way to moving the NSView and also being able to set a delegate. Any help would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半岛未凉 2024-11-15 01:49:03

对视图所做的更改在当前运行循环结束时生效。这同样适用于应用于图层的任何动画。

如果您对视图的图层进行动画处理,则视图本身不受影响,这就是动画完成时视图似乎跳回其原始位置的原因。

考虑到这两件事,您可以通过将视图的框架设置为动画完成时您想要的效果,然后向视图的图层添加显式动画来获得您想要的效果。

当动画开始时,它将视图移动到起始位置,将其动画到结束位置,当动画完成时,视图将具有您指定的帧。

- (IBAction)animateTheView:(id)sender
{
    // Calculate start and end points.  
    NSPoint startPoint = theView.frame.origin;
    NSPoint endPoint = <Some other point>;    

    // We can set the frame here because the changes we make aren't actually
    // visible until this pass through the run loop is done.
    // Furthermore, this change to the view's frame won't be visible until
    // after the animation below is finished.
    NSRect frame = theView.frame;
    frame.origin = endPoint;
    theView.frame = frame;

    // Add explicit animation from start point to end point.
    // Again, the animation doesn't start immediately. It starts when this
    // pass through the run loop is done.
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    [animation setFromValue:[NSValue valueWithPoint:startPoint]];
    [animation setToValue:[NSValue valueWithPoint:endPoint]];
    // Set any other properties you want, such as the delegate.
    [theView.layer addAnimation:animation forKey:@"position"];
}

当然,要使此代码正常工作,您需要确保您的视图及其超级视图都有图层。如果超级视图没有图层,您将得到损坏的图形。

Changes made to views take effect at the end of the current run loop. The same goes for any animations applied to layers.

If you animate a view's layer, the view itself is unaffected which is why the view appears to jump back to its original position when the animation completes.

With these two things in mind, you can get the effect you want by setting the view's frame to what you want it to be when the animation is done and then adding an explicit animation to the view's layer.

When the animation begins, it moves the view to the starting position, animates it to the end position and when the animation is done, the view has the frame you specified.

- (IBAction)animateTheView:(id)sender
{
    // Calculate start and end points.  
    NSPoint startPoint = theView.frame.origin;
    NSPoint endPoint = <Some other point>;    

    // We can set the frame here because the changes we make aren't actually
    // visible until this pass through the run loop is done.
    // Furthermore, this change to the view's frame won't be visible until
    // after the animation below is finished.
    NSRect frame = theView.frame;
    frame.origin = endPoint;
    theView.frame = frame;

    // Add explicit animation from start point to end point.
    // Again, the animation doesn't start immediately. It starts when this
    // pass through the run loop is done.
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    [animation setFromValue:[NSValue valueWithPoint:startPoint]];
    [animation setToValue:[NSValue valueWithPoint:endPoint]];
    // Set any other properties you want, such as the delegate.
    [theView.layer addAnimation:animation forKey:@"position"];
}

Of course, for this code to work you need to make sure both your view and its superview have layers. If the superview doesn't have a layer, you'll get corrupted graphics.

苏辞 2024-11-15 01:49:03

我认为你需要在最后调用 setPosition (设置动画后)。
另外,我认为您不应该显式地对视图的图层进行动画处理,而是通过使用动画器并设置动画来对视图本身进行动画处理。您也可以将委托与动画师一起使用:)

// create controlPosAnim
[controlView setAnimations:[NSDictionary dictionaryWithObjectsAndKeys:controlPosAnim, @"frameOrigin", nil]];
[[controlView animator] setFrame:newFrame];

I think you need to call the setPosition at the end (after setting the animation).
Also, I don't think you should animate explicitely the layer of the view, but instead the view itself by using animator and setting the animations. You can use delegates too with animator :)

// create controlPosAnim
[controlView setAnimations:[NSDictionary dictionaryWithObjectsAndKeys:controlPosAnim, @"frameOrigin", nil]];
[[controlView animator] setFrame:newFrame];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文