Создайте потрясающий визуальный секундомер с помощью CoreAnimation и CAShapeLayers
CoreAnimations великолепны, и его можно использовать на слоях ваших представлений, чтобы обеспечить плавную анимацию для представлений и его подпредставлений, и это помогает украсить ваше приложение, а также обеспечивает согласованный пользовательский интерфейс. Вот определение CoreAnimation из документации для разработчиков Apple:
Core Animation обеспечивает высокую частоту кадров и плавную анимацию, не перегружая процессор и не замедляя работу вашего приложения. Большая часть работы, необходимой для рисования каждого кадра анимации, делается за вас. Все, что вам нужно сделать, это настроить несколько параметров анимации (например, начальную и конечную точки) и сообщить Core Animation о начале. Core Animation сделает все остальное
Я начал использовать их недавно, и позвольте мне сказать вам одну вещь, это довольно круто. Сначала я неохотно думал, что это нелегко и потребуется много времени, чтобы выучить его, прежде чем я начну его использовать, но я ошибался: как только я начал изучать и применять концепции, я смог понять это относительно быстро.
Примечание. Это руководство основано на UIKit. Если вы используете SwiftUI, вы все равно можете пройти через него, но у него другой способ сделать это.
Хорошо, давайте посмотрим, как мы можем использовать CoreAnimations, CAShapeLayers для создания визуального секундомера.
Предпосылки
Вам не обязательно иметь глубокие познания в области разработки приложений для iOS, поэтому смело следите за ними! Все, что вам нужно, это MacBook, Xcode и некоторые знания Auto Layouts.
Вступление
Небольшое введение в секундомер, который мы собираемся создать.
Мы собираемся использовать 3 слоя CAShapeLayer для секундомера и анимировать его с помощью CoreAnimation.
- Слой дорожки - это внешний слой с серым кружком, на котором отображается пустая дорожка.
- Слой заполнения круга - слой, который заполняется с течением времени.
- Round Layer - слой, который показывает текущее положение слоя заливки круга.
Мы также будем использовать 3 набора таймеров для секундомера -
- Один таймер, который вызывается каждую 1 секунду для обновления секунд секундомера.
- Один таймер, который вызывается каждые 60 секунд для перезапуска слоя заливки круга.
- Один таймер используется для обновления миллисекунд секундомера.
Руководство
Начните с создания одностраничного приложения в Xcode и выберите Раскадровки в качестве пользовательского интерфейса.
Дизайн пользовательского интерфейса
Откройте Main.storyboard и настройте представления
Вот что мы использовали -
- Представление контейнера секундомера - UIView, который будет содержать секундомер.
- Метка времени секундомера - UILabel, который будет отображать минуты и секунды при запуске секундомера.
- Метка секунд секундомера - UILabel, который будет отображать миллисекунды при запуске секундомера.
- Кнопка управления секундомером - UIButton, который будет использоваться для запуска / остановки секундомера.
Напишите код
Начните с подключения выходов представления в viewController
Мы будем использовать CAShapeLayers, чтобы создать слой и добавить его в слой представления контейнера. Вот небольшое введение в CAShapeLayer -
CAShapeLayer
Слой, который рисует кубический сплайн Безье в своем координатном пространстве. Фигура складывается между содержимым слоя и его первым подслоем.
Мы добавим 3 слоя CAShapeLayer, 3 таймера, 3 цвета и некоторые переменные для хранения секунд -
Переменная initialValue используется для установки положения круглого слоя, так как он будет ведущим слоем с заливкой круга.
Теперь давайте настроим слои и добавим их в наш containerView -
Давайте посмотрим на приведенный выше код -
ArcPath определяет круговой путь внутри containerView, он имеет радиус 140, начальный угол как 0 и конечный угол как 360 для создания круга.
Затем мы настраиваем слой дорожки -
- ArcPath, определенный выше, назначается как путь трека.
- StrokeColor используется для определения цвета дорожки.
- LineWidth используется для указания ширины дорожки.
- LineCap используется для указания стиля обводки - круга, квадрата или стыка.
- FillColor используется для указания backgroundColor слоя.
Настройте слой заливки круга -
Он почти такой же, как слой дорожки, с несколькими дополнительными свойствами -
- Конец обводки используется для указания процента слоя, который будет заполнен обводкой. Он изменяется от 0 до 1 (от 0% до 100%).
Настройте круглый слой -
- Начало обводки используется для указания начальной точки обводки. Диапазон значений 0–1.
Наконец, мы добавляем все слои в containerView и настраиваем кнопку.
Теперь давайте определим функцию розетки при нажатии кнопки «Пуск» -
Довольно просто: если для секундомера установлено значение false, мы запускаем секундомер и наоборот.
Скоро мы начнем с функций секундомера, но перед этим есть расширение для добавления нулей к времени, если оно меньше 10, чтобы время всегда отображалось двузначными числами -
extension Int{ func appendZeros() -> String { if (self < 10) { return "0\(self)" } else { return "\(self)" } } }
Теперь вернемся к # 1, мы добавим наши переменные анимации непосредственно перед функцией viewDidLoad -
StrokeStartAnimation анимирует свойство strokeStart слоя -
- Продолжительность определяет продолжительность анимации.
- ToValue указывает конечное значение, которое анимация должна достичь по истечении времени действия.
- Fillmode определяет режим анимации - вперед, назад или и то, и другое.
StrokeEndAnimation анимирует свойство strokeEnd слоя, свойства те же, что и выше, с той лишь разницей, что они будут нацелены на свойство strokeEnd.
Логика здесь -
- К слою заливки круга применена анимация strokeEnd, так что он заполняет круг за 60 секунд.
- К круглому слою применены анимации strokeStart и strokeEnd, так что он ведет к слою заливки круга. Если вы не предоставите свойство strokeStart этому слою, он будет вести себя например Слой заливки круга, поскольку начальная точка фиксирована.
Теперь давайте посмотрим на функции секундомера -
- СекундомерSecondTimer имеет timeInterval 0,01 и изменяется от 0 до 100 миллисекунд.
- StopwatchTimer имеет timeInterval, равный 1 секунде, и используется для добавления секунд и минут к секундомеру.
- Функция анимации вызывается сначала, а затем каждые 60 секунд с помощью stopWatchAnimationTimer.
Функция animateStopwatch добавляет strokeEndAnimation в слой заливки круга и strokeStartAnimation, strokeEndAnimation - в круглый слой.
Наконец, давайте посмотрим на функцию сброса секундомера -
Эта функция сбрасывает все значения в исходное значение и удаляет анимацию из слоев.
Вот и все! Мы создали красивый визуальный секундомер с помощью CAShapeLayers и CoreAnimations.
Вот конечный результат -
Ресурсы
- Полный исходный код ViewController -
2. Репозиторий Github -
3. Документация для разработчиков Apple -
Заключение
Подведем итоги тому, что мы узнали сегодня.
Мы начали с создания компонентов секундомера в раскадровке, добавили StopwatchContainer и UILabels для отображения времени и UIButton для управления секундомером.
Затем мы объявили CAShapeLayers для секундомера, таймеров и переменных для использования секундомера, а также 2 переменных CABasicAnimation для анимации слоев.
Затем в методе viewDidLoad мы настроили слои и кнопку и добавили ее в ContainerView.
Далее мы написали код для управления секундомером в функции вывода для UIButton.
Наконец, мы написали функции для запуска секундомера, который запускает таймеры, обновляет метки, а также добавляет анимацию к слоям. Мы также определили функцию resetStopwatch, которая сбрасывает секундомер.
Я надеюсь, что вы смогли хорошо понять концепции CAShapeLayers и CoreAnimation, это только отправная точка, как только вы начнете играть со свойствами слоев и CoreAnimation, вы сможете создавать множество интересных эффектов и переходов.
Спасибо, что прочитали эту статью. Надеюсь увидеть вас снова в следующей статье!