Явная анимация NSView с использованием базовой анимации

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


person btschumy    schedule 19.05.2011    source источник


Ответы (2)


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

// create controlPosAnim
[controlView setAnimations:[NSDictionary dictionaryWithObjectsAndKeys:controlPosAnim, @"frameOrigin", nil]];
[[controlView animator] setFrame:newFrame];
person Michael Villar    schedule 19.05.2011
comment
Спасибо за ответ. Я добился этого, немного изменив код. Я думаю, что примеры Apple во время WWDC говорили вам манипулировать представлением перед установкой анимации. Итак, как можно использовать делегаты с аниматором? Я искал примеры этого повсюду и не нашел. Я также видел множество сообщений, в которых говорилось, что это невозможно. - person btschumy; 23.05.2011
comment
Установите делегата в свой controlPosAnim, добавьте его в анимацию controlView, будут вызваны методы делегата. - person Michael Villar; 25.05.2011

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

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

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

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

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

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

person Colin    schedule 17.02.2012
comment
Вау, спасибо за последний комментарий как к супер, так и к дочерним слоям, в противном случае вы получите поврежденную графику. Это помогло мне исправить совершенно не связанную проблему. Спасибо! - person migs647; 08.07.2014