Используя объект NSAnimation
NSAnimation
класс обеспечивает сложное поведение для анимаций, происходящих за конечный отрезок времени. OS X использует объекты Animation для реализации анимаций перехода для элементов пользовательского интерфейса. Можно определить объекты пользовательской анимации реализовать анимации для собственного кода. В отличие от этого NSTimer
, уведомления анимации могут произойти в неправильных интервалах, позволив Вам создать анимации, которые, кажется, убыстряются или замедляются.
Следующие разделы покрывают основные шаги для создания пользовательского NSAnimation
объект и использование его для управления анимированным контентом. Если Вы хотите анимировать свои представления и окна, необходимо видеть если NSViewAnimation
класс (который является подклассом NSAnimation
) предложите поведение, в котором Вы нуждаетесь. Просмотрите объекты Animation, обеспечивают сложное поведение для изменения размеров и перемещения представлений в течение долгого времени и описаны в Анимации Представлений и Windows.
Создание и конфигурирование таймера анимации
NSAnimation
объект имеет несколько важных атрибутов:
Текущий прогресс — значение между 0,0 и 1.0, который указывает процент завершенной анимации.
Частота кадров — число обновлений в секунду.
Продолжительность — период (в секундах), по которому происходит анимация.
Кривая анимации — относительная скорость анимации по ее курсу; например, анимация могла медленно убыстряться вначале, постепенно замедляться около ее конца или оставаться той же скоростью повсюду.
Режим Blocking — режим, в котором анимация работает с точки зрения скорости отклика приложения к пользовательским действиям.
Когда Вы конфигурируете новое NSAnimation
объект, необходимо, как минимум, установить его продолжительность, кривую анимации, частоту кадров и атрибуты режима блокирования. Необходимо также присвоить делегата для контроля динамики анимации. Когда анимация начинается, заканчивается, явно останавливается или достигает метки прогресса, объект Animation отправляет сообщение текущему делегату. (См. Установку и Обработку Знаков Прогресса для получения информации о метках прогресса). Если Вы не хотите использовать делегата, необходимо разделить на подклассы NSAnimation
получить информацию о прогрессе; посмотрите Разделение на подклассы NSAnimation.
Перечисление 1 показывает выборочный метод, создающий и конфигурирующий стандарт NSAnimation
объект. Объект, создавший действия анимации как делегата и обрабатывающий любые сообщения о ходе выполнения.
Перечисление 1 , Инициализирующее объект NSAnimation
- (id)init |
{ |
self = [super init]; |
if (self) |
{ |
// theAnim is an NSAnimation instance variable. |
theAnim = [[NSAnimation alloc] initWithDuration:10.0 |
animationCurve:NSAnimationEaseIn]; |
[theAnim setFrameRate:20.0]; |
[theAnim setAnimationBlockingMode:NSAnimationNonblocking]; |
[theAnim setDelegate:self]; |
} |
return self; |
} |
initWithDuration:animationCurve:
метод является определяемым инициализатором для NSAnimation
класс. Этот метод позволяет Вам установить два из атрибутов анимации. Для других атрибутов можно использовать значения по умолчанию или установить значение атрибута явно с помощью надлежащих методов доступа. Атрибуты по умолчанию следующие:
Режим блокирования значения по умолчанию
NSAnimationBlocking
.Частота кадров по умолчанию является рыночной стоимостью. Эта частота кадров обычно - 60 Гц, но нельзя положиться на точное значение.
Как только Вы подготовились NSAnimation
объект для использования, можно выполнить его путем отправки ему a startAnimation
сообщение. Если необходимо остановить его, прежде чем анимация завершит свою запланированную продолжительность, отправьте объект a stopAnimation
сообщение. Делегат NSAnimation
объект (если Вы существуете) получает сообщения, сообщающие ему об обоих из этих событий, а также сообщению, говорящему его, если анимация завершилась, как запланировано.
Установка и обработка Знаков прогресса
NSAnimation
имеет понятие меток прогресса — значения с плавающей точкой (типа NSAnimationProgress
) это указывает сумму процента анимации, которая завершена. Когда Вы запускаете анимацию, и она достигает метки прогресса (в частности, ее текущий прогресс равен метке прогресса), объект Animation отправляет сообщение своему делегату. Делегат может тогда обновить пользовательский индикатор хода выполнения, играть звук или выполнить некоторый другой эффект, надлежащий той точке анимации.
Когда Вы сначала создаете и инициализируете объект, обычно Вы устанавливаете метки прогресса объекта Animation. Перечисление 2 показывает один подход, устанавливающий 20 равномерно распределенных меток прогресса.
Перечисление 2 , Устанавливающее метки прогресса объекта NSAnimation
- (void)awakeFromNib |
{ |
NSAnimationProgress progMarks[] = { |
0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, |
0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0 }; |
int i, count = 20; |
// theAnim is an NSAnimation instance variable |
theAnim = [[NSAnimation alloc] initWithDuration:10.0 |
animationCurve:NSAnimationEaseInOut]; |
[theAnim setFrameRate:20.0]; |
[theAnim setDelegate:self]; |
for (i=0; i<count; i++) |
[theAnim addProgressMark:progMarks[i]]; |
} |
Вместо того, чтобы добавить метку прогресса оценивает в цикле, как в этом примере, можно установить их в одном вызове при помощи setProgressMarks:
метод, берущий массив NSNumber
инкапсуляция объектов float
значения.
Когда рабочий объект Animation достигает метки прогресса, он отправляет animation:didReachProgressMark:
обменивайтесь сообщениями его делегату. Делегат должен обработать это сообщение в пути, надлежащем метке прогресса, переданной в. Перечисление 3 иллюстрирует, как делегат реализует этот метод для игры звука поезда равномерно.
Делегат перечисления 3 реализация animation:didReachProgressMark:
- (void)animation:(NSAnimation *)animation |
didReachProgressMark:(NSAnimationProgress)progress |
{ |
if (animation == theAnim) |
[[NSSound soundNamed:@"chug"] play]; |
} |
Разделение на подклассы NSAnimation
Несмотря на то, что можно использовать NSAnimation
возразите как есть во многих целях, разделение на подклассы его является более общим сценарием. Существует три основных причины разделить на подклассы NSAnimation
:
Достигнуть плавных анимаций путем перерисовки в интервалах на кадр
Указать допустимые режимы цикла выполнения при выполнении анимации на основном потоке в неблокировании режима
Возвратить значения пользовательской кривой без издержек делегата, отвечающего на
animation:valueForProgress:
Процедуры для выполнения первых двух из этих целей описаны в следующих разделах. Для возврата значений пользовательской кривой, не реализовывая метод делегата необходимо переопределить currentValue
метод. Посмотрите NSAnimation
документация класса для получения дополнительной информации.
Плавные анимации
Как упомянуто в Установке и Обработке Знаков Прогресса, можно присоединить серию меток прогресса к NSAnimation
возразите и сделайте, чтобы делегат реализовал animation:didReachProgressMark:
метод для перерисовки объекта в каждой метке прогресса. Однако это не лучший способ анимировать объект. Если Вы не определяете большой номер меток прогресса (30 в секунду или больше), анимация, вероятно, собирается казаться судорожной.
Лучший подход должен разделить на подклассы NSAnimation
и переопределение setCurrentProgress:
метод, как проиллюстрировано в Перечислении 4. NSAnimation
объект вызывает этот метод после каждого кадра для изменения значения прогресса. Путем прерывания этого сообщения можно выполнить любую перерисовку, или обновление Вас нуждаются для того кадра. Если Вы действительно переопределяете этот метод, несомненно, вызовут реализацию super
так, чтобы это могло обновить текущий прогресс.
Перечисление 4 , Переопределяющее setCurrentProgress: метод
- (void)setCurrentProgress:(NSAnimationProgress)progress |
{ |
// Call super to update the progress value. |
[super setCurrentProgress:progress]; |
// Update the window position. |
NSRect theWinFrame = [[NSApp mainWindow] frame]; |
NSRect theScreenFrame = [[NSScreen mainScreen] visibleFrame]; |
theWinFrame.origin.x = progress * |
(theScreenFrame.size.width - theWinFrame.size.width); |
[[NSApp mainWindow] setFrame:theWinFrame display:YES animate:YES]; |
} |
Пользовательские наборы режима цикла выполнения
NSAnimation
объект с режимом блокирования NSAnimationNonblocking
выполнения в основном потоке процесса в режиме цикла выполнения, принимающем ввод данных пользователем. Прежде чем это выполнит анимацию, объект Animation отправляет себе a runLoopModesForAnimation
сообщение для получения в настоящее время допустимых режимов цикла выполнения. По умолчанию, этот метод возвраты nil
, который говорит NSAnimation
использовать режим по умолчанию (NSDefaultRunLoopMode
), модальный режим панели (NSModalPanelRunLoopMode
), и событие, отслеживающее режим цикла выполнения (NSEventTrackingRunLoopMode
).
Можно переопределить этот метод для возврата различного набора выполненных режимов цикла, которые могут включать пользовательские режимы. Перечисление 5 показывает реализацию, возвращающую массив по умолчанию режимов минус режим отслеживания события (NSEventTrackingRunLoopMode
).
Перечисление 5 Возвращая режимы цикла выполнения из runLoopModesForAnimating
- (NSArray *)runLoopModesForAnimating |
{ |
return [NSArray arrayWithObjects: NSDefaultRunLoopMode, |
NSModalPanelRunLoopMode, nil]; |
} |
Соединение анимаций
Можно соединить два объекта Animation так, чтобы один из них начал работать (или прекращает работать), когда другие пределы указанная метка анимации. Эта функция NSAnimation
полезно для координирования различных эффектов. Перечисление 6 иллюстрирует как startWhenAnimation:reachesProgress:
когда другая анимация достигает промежуточного этапа, метод используется для запуска анимации.
Перечисление 6 , Соединяющее две анимации
- (IBAction)startAnim:(id)sender |
{ |
// theAnim and theOtherAnim are variables of type NSAnimation. |
[theOtherAnim startWhenAnimation:theAnim reachesProgress:0.5]; |
[theAnim startAnimation]; |
} |
Если Вы хотите вместо этого остановить анимацию, когда другая анимация достигает метки прогресса, используйте stopWhenAnimation:reachesProgess:
метод. Можно соединить анимации неопределенно, один за другим. Однако может быть, только один «запускается» и одна анимация «остановки» в любой момент времени.
Если у Вас есть делегат, отвечающий на animation:didReachProgressMark:
сообщения, это должно различить среди многократных анимаций, как в Перечислении 7.
Перечисление 7 , Обрабатывающее метки прогресса одновременно рабочих анимаций
- (void)animation:(NSAnimation *)animation |
didReachProgressMark:(NSAnimationProgress)progress |
{ |
if (animation == theOtherAnim) |
{ |
// Do an effect appropriate to progress mark. |
} |
else if (animation == theAnim) |
{ |
// Do an effect appropriate to progress mark. |
} |
} |