Создайте потрясающий визуальный секундомер с помощью 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.

Вот конечный результат -

Ресурсы

  1. Полный исходный код ViewController -

2. Репозиторий Github -



3. Документация для разработчиков Apple -



Заключение

Подведем итоги тому, что мы узнали сегодня.

Мы начали с создания компонентов секундомера в раскадровке, добавили StopwatchContainer и UILabels для отображения времени и UIButton для управления секундомером.

Затем мы объявили CAShapeLayers для секундомера, таймеров и переменных для использования секундомера, а также 2 переменных CABasicAnimation для анимации слоев.

Затем в методе viewDidLoad мы настроили слои и кнопку и добавили ее в ContainerView.

Далее мы написали код для управления секундомером в функции вывода для UIButton.

Наконец, мы написали функции для запуска секундомера, который запускает таймеры, обновляет метки, а также добавляет анимацию к слоям. Мы также определили функцию resetStopwatch, которая сбрасывает секундомер.

Я надеюсь, что вы смогли хорошо понять концепции CAShapeLayers и CoreAnimation, это только отправная точка, как только вы начнете играть со свойствами слоев и CoreAnimation, вы сможете создавать множество интересных эффектов и переходов.

Спасибо, что прочитали эту статью. Надеюсь увидеть вас снова в следующей статье!