7

我正在尝试滑入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并且还能够设置委托。任何帮助,将不胜感激。

4

2 回答 2

8

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.

于 2012-02-17T19:24:38.537 回答
5

我认为您需要在最后调用 setPosition(在设置动画之后)。另外,我不认为你应该明确地为视图层设置动画,而是通过使用动画器和设置动画来显示视图本身。您也可以在动画师中使用代表:)

// create controlPosAnim
[controlView setAnimations:[NSDictionary dictionaryWithObjectsAndKeys:controlPosAnim, @"frameOrigin", nil]];
[[controlView animator] setFrame:newFrame];
于 2011-05-19T22:37:35.060 回答