7 сентября 2016 г. Анимация в iOS: нативные решения и сторонние фреймворки
Всем привет! Сегодня мы будем рассматривать анимацию в iOS. Взглянем на несколько довольно-таки легких примеров, пройдемся по преимуществам и недостаткам того, что предлагает нам Apple и также рассмотрим несколько, на мой взгляд, достойных фреймворков сторонних разработчиков. Кроме того, я покажу примеры использования UIKit Dynamics и Motion Effects, которые доступны с версии iOS 7.
UIKit Dynamics — это физический движок, позволяющий воздействовать на элементы путем добавления поведений ( behaviors ), таких как gravity , springs , forces , и т.д. А движок при этом уже сам заботится обо всем остальном.
Motion Effects — позволяет вам создавать parallax effects, которые мы, например, видим на рабочем столе, когда немного поворачиваем телефон. Home screen при этом будто бы немного сдвигается в одну сторону, а иконки — в противоположную. За счет этого создается эффект глубины, который вы без особого труда можете использовать в своих приложениях.
UIKit Dynamics
Добавим в storyboard UIView , дадим ему серый цвет и привяжем его с помощью constrains . Тут нужно быть внимательными, так как иногда физический движок плохо воспринимает такую привязку, поэтому нужно просто добавить элемент где-нибудь в viewDidLoad() и задать размер с помощью frame .
Далее добавляем несколько свойств в класс ViewController :
В viewDidLoad() инициализируем эти свойства:
Запускаем на симуляторе анимацию и видим, как серый квадрат благополучно падает куда-то за экран. Что ж, уже весело, но пока не очень.
Добавляем UICollisionBehavior и ставим его свойство translatesReferenceBoundsIntoBoundary в true . Это свойство отвечает за границы системы, если его значение true — границами будут view нашего ViewController ’а. Не забываем добавить наше новое поведение к объекту animator — он проводит все расчеты:
Теперь серый квадрат ударяется о нижнюю часть экрана — отлично!
Идем дальше и добавим барьер. Как я писал выше, при добавлении барьера через storyboard движок не смог его точно просчитать, так что добавим его вручную:
Барьер добавлен, сейчас нужно добавить collision :
Теперь все отлично, система работает, кубик падает и происходит столкновение. Идем дальше и добавим кубику немного «эластичности»:
Кроме параметра elasticity , в нашем арсенале есть еще пару свойств с которыми можно поиграться:
- elasticity
- friction
- density
- resistance
- angularResistance
У нас также есть возможность отслеживать момент, когда кубик сталкивается с препятствиями. Подписываем контроллер как делегат:
И реализуем следующий метод:
Так при каждом столкновении мы будем менять цвет кубика на красный:
Теперь поговорим о том, что происходит за сценой. Каждое поведение ( behavior ) имеет свойство action . Мы можем добавить блок кода, который наша анимация будет выполнять во время каждого шага (около 400 миллисекунд). Добавим:
На каждый шаг анимации будет добавляться новый кубик, который использует координаты нашего серого кубика, в то время, как наш «главный герой» будет спрятан, чтобы не мешал любоваться созданным эффектом :)
Так будет выглядеть финальный результат:
Motion Effects
Для следующего примера желательно иметь реальный девайс. На симуляторе повторить этот эффект не удастся, можете не стараться наклонять голову или монитор — я пробовал, ничего не вышло :)
Так выглядит наш storyboard:
Также обратите внимание на constraints для backImView :
Сделано это для того, чтобы при сдвиге backImView (картинка с небом) не показывала белый цвет view контроллера. А теперь код:
Мы добавим motion effect к заднему виду ( backImView ) и к фронтальному ( frontImView ). midImView нам не интересен, он остается статичным.
Создаем вспомогательный метод addMotionEffectToView и инициализируем его нашими UIImageView с дополнительными свойствами — и все! Хорошего вам parallax-эффекта )
Начнем с рассмотрения сторонних фреймворков. Первой «жертвой» нашего обзора будет фреймворк Pop от Facebook. Вдобавок к стандартной анимации ( POPBasicAnimation ) фреймворк поддерживает POPSpringAnimation и POPDecayAnimation , что позволяет добиться реалистичной и физически корректной анимации.
Для примера будем использовать cocoapods. Добавляем в Podfile:
В storyboard добавлено несколько элементов и segue для перехода на экран со скотч-терьером, смотрим и умиляемся :)
По клику на каждый элемент происходит конкретная анимация. Начнем c метода animateLabel() :
Вначале создаем объект POPSpringAnimation , инициализировав его именем того свойства, с которым будем работать. По клику на kPOPLayerScaleX перейдите к файлу, в котором увидите список всех свойств, которые можете анимировать.
Обратите внимание, что можно анимировать как CALayer property names, так и UIView property names — от этого зависит, будем ли мы применять анимацию к объекту или его слою. completionBlock я добавил просто для наглядности, чтобы знать когда закончится анимация.
Перед добавлением анимации желательно удалить уже существующую, даже если она и не применялась — так, на всякий случай:
Ключ может быть произвольным. В итоге наш UILabel-объект начинает растягиваться по оси Х.
По клику на UISegmentedControl запускаем мигающую анимацию свойства alpha.
Продвигаемся к более сложному примеру:
Опять будем использовать POPSpringAnimation и, на этот раз, анимировать kPOPLayerBounds . Эта анимация отвечает за изменения размеров (frame) UIView . Вначале мы придаем UIView вид, похожий на status bar.
Далее анимируем cornerRadius — тут используем просто POPBasicAnimation . И подписываемся делегатом на pop_animationDidStop . Реализовываем сам метод:
Далее в теле метода вызываем еще одну анимацию:
В итоге у нас выходит вот такая вот метаморфоза простого оранжевого кубика в status bar :)
И последний вид анимации, который я хотел бы рассмотреть, это custom segue animation.
Вот как создание подобного segue выглядит в storyboard:
CustomSegue — это класс, унаследованный от UIStoryboardSegue , который отвечает за анимацию при переходе между контроллерами.
Чтобы сделать простую анимацию, мы перепишем всего один метод:
В итоге нам удалось немного оживить анимацию. Конечно, в реальном приложении нам пришлось бы еще подчиняться протоколу UIViewControllerTransitioningDelegate и реализовывать два его метода: animationControllerForPresentedController и animationControllerForDismissedController . Тут я лишь хотел показать, как относительно легко можно добиться желаемого результата с использованием фреймворка Pop.
Cheetah
Лично мне очень понравился фреймворк Cheetah. Он удивительно компактный в плане кода и дает вполне приличные результаты.
Откройте проект Cheetah_project. В storyboard у нас содержится всего одна кнопка, по которой мы и будем кликать все время :) Код самой кнопки показан ниже:
И, прописав всего несколько строчек кода, мы получаем анимацию, на которую стандартными методами потратили бы намного больше времени. А главное, чем больше у вас написано кода, тем сложнее его править.
Также советую обратить внимание на framework Spring. Разработчики подготовили очень приятное приложение, с помощью которого вы можете исследовать возможности их продукта и даже смотреть на код, заинтересовавшего вас эффекта. А также на DCAnimationKit — очень простой в использовании framework с кучей уже готовых решений.
Не стоит забывать, что все эти уже готовые решения написаны с использованием низкоуровневых С-функций, таких как CGAffineTransformMakeRotation() , и если вы хотите всерьез заниматься анимацией, то вам никуда от них не деться.
Или, по крайней мере, вы должны знать методы уже более «высокого» уровня, такие как:
- UIView.animateWithDuration
- UIView.animateKeyframesWithDuration
- UIView.addKeyframeWithRelativeStartTime
А также понимать, что такое CABasicAnimation() , CAPropertyAnimation() и т.д.
Но если вам все-таки нужно быстро применить какую-то функцию, то ваш путь — одно из более «ленивых решений», о которых я писал выше.
Нужен MVP, разработка под iOS, Android или прототип приложения? Ознакомьтесь с нашим портфолио и сделайте заказ уже сегодня!