Явная анимация NSView с использованием базовой анимации - PullRequest
7 голосов
/ 20 мая 2011

Я пытаюсь вставить 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, а также возможность установки делегата. Любая помощь будет оценена.

Ответы [ 2 ]

8 голосов
/ 17 февраля 2012

Изменения, внесенные в представления, вступают в силу в конце текущего цикла выполнения.То же самое касается любой анимации, примененной к слоям.

Если вы анимируете слой представления, само представление не изменяется, поэтому представление, по-видимому, возвращается к своей исходной позиции после завершения анимации.

Имея в виду эти две вещи, выВы можете получить желаемый эффект, установив кадр представления таким, каким вы хотите его видеть, когда анимация будет завершена, а затем добавив явную анимацию к слою представления.

Когда анимация начинается, она перемещает вид наначальная позиция, анимирует ее до конечной позиции, и когда анимация завершена, представление имеет заданную вами рамку.

- (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"];
}

Конечно, чтобы этот код работал, вам нужно убедиться, что оба видаи его суперпредставление имеет слои.Если в суперпредставлении нет слоя, вы получите поврежденную графику.

5 голосов
/ 20 мая 2011

Я думаю, вам нужно вызвать setPosition в конце (после настройки анимации).Кроме того, я не думаю, что вы должны явно анимировать слой вида, но вместо этого сам вид, используя аниматор и настройку анимации.Вы также можете использовать делегатов с аниматором:)

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