Створення динамічних анімацій в WatchKit

Виявив цю статтю в чернетках. Якщо її не опублікувати зараз, то вже ніколи – вона безповоротно застаріє і місце їй тільки на смітнику.

Не так давно компанія 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 the cache 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бит.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.