Какие сложные UI-задачи вы решали в UIKit?

Ответ

1. Кастомный анимированный таймер с интерактивным управлением

  • Задача: Создать визуализацию таймера с плавной анимацией прогресса и возможностью изменения времени жестом.
  • Решение: Использовал CAShapeLayer для отрисовки кругового трека и прогресса. Анимация strokeEnd через CABasicAnimation с CAMediaTimingFunction для плавности. Для интерактивности добавил UIPanGestureRecognizer, который пересчитывает время на основе смещения.
  • Пример кода анимации:
    let progressLayer = CAShapeLayer()
    let animation = CABasicAnimation(keyPath: "strokeEnd")
    animation.duration = 10.0
    animation.fromValue = 0
    animation.toValue = 1
    animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
    progressLayer.add(animation, forKey: "progressAnimation")

2. Сложная таблица с sticky-заголовками секций, меняющими стиль

  • Задача: Реализовать таблицу с заголовками секций, которые прилипают к верху и динамически меняют внешний вид при скролле.
  • Решение: Комбинация UITableView с кастомным UICollectionView в качестве header. Синхронизация скролла через KVO наблюдение за contentOffset. Изменение стиля заголовка (например, фона или шрифта) вычислялось на основе позиции скролла.

3. Онбординг с параллакс-эффектом и прерываемыми анимациями

  • Задача: Создать плавный анимированный онбординг, где переходы между экранами можно прервать свайпом.
  • Решение: Использовал UIViewPropertyAnimator для управления интерактивными переходами. Параллакс достигался за счет применения разных CGAffineTransform к слоям фона и переднего плана. Ключевой момент — корректная пауза, отмена или завершение анимации при прерывании пользователем.

Ответ 18+ 🔞

Ну и день сегодня, ёпта, как будто меня заставили всю эту документацию на асфальте гвоздём выцарапывать. Сижу, блядь, думаю, как бы это всё тебе так объяснить, чтобы и смешно было, и чтобы ты не сдох от скуки.

Вот смотри, первая задача — таймер кастомный, анимированный. Ну, типа, чтоб красиво и пальцем покрутить можно было. Представь себе, блядь, обычный круг, который закрашивается. Так вот, я этот круг нарисовал не просто так, а через CAShapeLayer, это такая, блядь, штука, которая рисует линии. А чтобы он плавно закрашивался, я ему говорю: «Слушай, дружок-пирожок, анимируй-ка мне свой strokeEnd». И даю ему CABasicAnimation. А чтоб не резко, а с чувством, с толком, с расстановкой, подсовываю CAMediaTimingFunction с именем .easeInEaseOut. Он такой: «А, понял, щас сделаю красиво».

А потом, сука, чтобы время менять жестом, я прикрутил UIPanGestureRecognizer. Ты пальцем водишь, а он, падла, считает, на сколько ты сдвинулся, и пересчитывает, сколько времени осталось. Всё гениальное — просто, как три копейки.

let progressLayer = CAShapeLayer()
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = 10.0
animation.fromValue = 0
animation.toValue = 1
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
progressLayer.add(animation, forKey: "progressAnimation")

Дальше, вторая история — таблица со sticky-заголовками. Ох, бля, это просто пиздец какой-то. Задача: заголовки секций должны прилипать к верху и, пока ты скроллишь, меняться, как хамелеон на дискотеке. Ну, я, естественно, взял UITableView. А для заголовков, чтоб совсем уж гибко, запилил целый UICollectionView и сунул его в хедер таблицы. А потом, сука, началось самое весёлое — синхронизация. Я через KVO, как конченый, стал следить за contentOffset у обоих этих скроллов. Один поехал — второй тут как тут. И на основе позиции скролла вычислял, какого хуя заголовку менять фон или шрифт. Волнение, блядь, на уровне пиздеца, пока всё не заработало.

И третий акт этого цирка — онбординг. Ну, типа, первые экраны в приложении, где всё летает и плавно перетекает. Задача: сделать параллакс (когда фон и передний план двигаются с разной скоростью, для глубины) и чтобы анимации можно было прервать на полпути, пальцем махнув. Тут, блядь, в игру вступает UIViewPropertyAnimator. Штука, которая анимациями управляет, как кукловод. Параллакс я сделал, применяя разные CGAffineTransform к слоям — одному больше, другому меньше. А самое, блядь, интересное — это когда пользователь решит всё это великолепие прервать. Аниматор должен уметь: взять паузу, послать всё нахуй и отменить действие, или, наоборот, доделать его с ускорением. Чувствуешь, какая ответственность? Один неверный шаг — и всё, пизда, интерфейс разъезжается, как дерьмо по волнам. Но я справился, ядрёна вошь!