Pull to refresh

Создание динамических анимаций в WatchKit

Reading time2 min
Views2.7K
Обнаружил эту статью в черновиках. Если её не опубликовать сейчас, то уже никогда – она безвозвратно устареет и место ей только на помойке.

Не так давно компания Apple представила WatchKit Framework для разработки приложений под свои фирменные часы Apple Watch. На данный момент iOS 8.3 SDK очень ограничен – весь код выполняется на iPhone/iPad, а на часах находится только интерфейс и картинки. Таким образом, при любом взаимодействии с элементами интерфейса – код выполняется на iOS-устройстве, а сигнал проходит от часов до устройства по Bluetooth и обратно. Создание анимаций из заранее нарезанных кадров – задача довольно примитивная и уже разжевана во многих блогах. Под катом речь о создании динамической анимации, кадры который подготавливаются на CoreGraphics.



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

NSInteger framesCount = 8;
CGRect rect = CGRectMake(0,0,100,100);
NSMutableArray *images = [NSMutableArray array];
UIGraphicsBeginImageContextWithOptions(rect.size, YES, [WKInterfaceDevice currentDevice].screenScale);
for (NSInteger frameIndex = 0; frameIndex < framesCount; frameIndex++)
{
    [self.backgroundImage drawAtPoint:CGPointZero];
    // or CGContextClearRect(UIGraphicsGetCurrentContext(), rect);

    // Draw frame #`frameIndex` of `framesCount`

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    [images addObject:image];
}
UIGraphicsEndImageContext();

Массив кадров необходимо преобразовать в одну картинку и ее отправить в кеш часов:

UIImage *image = [UIImage animatedImageWithImages:images duration:0.5];
[[WKInterfaceDevice currentDevice] addCachedImage:image name:@"myAnimation"];

В данном случае мы следуем рекомендации Apple:
IMPORTANT

When caching animated images, use the animatedImageWithImages:duration: method to create a single UIImage object with all of the animation frames and cache that image. Do not cache the images for the individual frames separately.

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

[self.image setImageNamed:@"myAnimation"];
[self.image startAnimating];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self.image stopAnimating];
    [self.image setImage:nil];
});

Этот метод не оставляет возможности точно выбрать число циклов анимации, но он работает. У меня так и не получилось воспользоваться методом `-startAnimatingWithImagesInRange:duration:repeatCount:` для отображения динамических анимаций. Больше всего расстраивает невозможность узнать, когда изображения реально попадают на часы. Из-за этого приходится занижать FPS и надеяться, что анимации будут загружены.

Вот кое-какие числа, полученные на симуляторе: простенькая анимация 150х150 (scale 2.0) из 8 кадров весит около 80кб, и время её загрузки около 1-2 сек. Понижение качества картинок PNG до 16бит (по 5 бит на компоненту и 1 на альфу) лишь увеличило суммарный вес анимации до 100Кб, что по крайней мере странно, возможно стоит попробовать палитровый PNG 8бит.
Tags:
Hubs:
+10
Comments0

Articles

Change theme settings