Изучите основные концепции SwiftUI, воссоздавая их знаменитый дышащий интерфейс

Возможно, вы видели приложение для дыхания на часах Apple Watch и играли с ним. Он включает серию эффектов и переходов, которые создают потрясающие впечатления.

Сегодня мы собираемся воссоздать это, используя базовые модификаторы SwiftUI чуть менее чем в 100 строк кода!

Мы разделим пользовательский интерфейс на следующие части:

  • FlowerView: компонент многократного использования, который создает цветок и обрабатывает всю логику анимации.
  • iOS ContentView: диспетчерская для управления состояниями FlowerView.

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

Создание FlowerView

Давайте начнем с создания нового проекта SwiftUI Xcode вместе с представлением с именем FlowerView и добавим все необходимые свойства:

  • isMinimized: логическое значение, отслеживающее состояние анимации.
  • numberOfPetals: эта переменная Double для анимации добавления / удаления лепестков.
  • animationDuration
  • circleDiameter: представляет размер каждого лепестка
  • absolutePetalAngle: длина окружности круга, деленная на количество лепестков, дает абсолютный угол, на который каждый лепесток будет повернут

На данный момент вам также необходимо обновить FlowerView_Previews и инициализировать свойства привязки константами.

Вперед к телу!

Цветок создается путем добавления нескольких кругов, которые вращаются и пересекаются вокруг центральной точки цветка. Мы создадим его, добавив массив кругов с помощью ForEach и вставив его в ZStack.

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

Точка привязки - это часть вида, которая должна быть зафиксирована на месте в качестве центра вращения.

Теперь нам нужно .offset() ZStack на радиус круга, так как мы хотим центрировать вид на основе центра цветка, а не центра нашего первоначального круга.

Прежде чем мы продолжим, вам также необходимо добавить модификатор .animation(), чтобы сделать наши представления анимированными всякий раз, когда мы изменяем свойство привязки.

Обновить ContentView

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

  • FlowerView
  • Ползунок для изменения numberOfPetals
  • Ползунок для изменения breathingDuration
  • Кнопка запуска анимации

Первый ползунок для управления numberOfPetals проверяет свойство onEditingChanged и определяет, когда пользователь закончил перетаскивать ползунок. Это позволяет нам .round() numberOfPetals, поэтому мы никогда не получим 2,5 лепестка или что-то подобное.

Что касается кнопки, моя реализация немного привередлива и состоит из DispatchQueues.. Причина в том, что сразу же isMinimized после того, как цветок перестанет сжиматься, нужно переключить, заставляя его снова расшириться.

Не стесняйтесь создавать свою собственную реализацию; исключение DispatchQueue вполне нормально.

Дыхательная анимация

Чего мы все ждали! Эта часть немного сложнее, но не волнуйтесь - SwiftUI делает это проще простого.

Мы разделим анимацию на три части:

  • Вращение цветочного вида
  • Масштаб цветочного вида
  • Вращение каждого отдельного лепестка

Выполнить первые две части довольно просто. Мы будем использовать модификаторы .rotationEffect() и .scaleEffect() вместе с тернарными операторами для изменения значений в зависимости от состояния isMinimized.

Добавьте это выше модификатора .animation() из FlowerView.

Чтобы создать эффект того, что все лепестки попадают в центр, достаточно просто изменить точку привязки на .center с .rotationEffect() каждого лепестка.

Вуаля!

Мы написали менее 100 строк кода, и у нас уже есть что-то, что невероятно похоже на нашу цель.

Еще кое-что…

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

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

Внесем эти изменения в FlowerView. Обязательно измените диапазон ForEach с 0<Int(numberOfPetals) на 0…Int(numberOfPetals).

Давайте также добавим к ContentView специальное свойство petalDuration , которое предназначено только для этой тонкой анимации. Чтобы убедиться, что это работает правильно, вам нужно будет динамически переключаться между breathDuration и petalDuration.

Заключение

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

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

Если вас интересует только исходный код, вот репозиторий GitHub.