Узнайте, как вращать объекты с опорной точкой

Compose прошел долгий путь, чтобы бросить вызов тому, как создавать декларативный пользовательский интерфейс. И анимационные объекты тоже не отстают. API предлагает унифицированный набор инструментов, который позволит вам отшлифовать ваши эффекты.

Сказав это, повторное открытие нового API может быть разочаровывающим. Вы столкнетесь с трудностями, пытаясь воспроизвести эффект, который вы знали, как выполнять с помощью прежнего API анимации. Вот что случилось со мной, когда я пытался раскачать предмет, как маятник. Вот чего я хотел добиться:

На первый взгляд анимация выглядит как бесконечное вращение вперед-назад от одного угла к другому. Ничего экстраординарного, правда? Посмотрим, как пойдет!

Создание компонуемого

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

Для этого составного объекта нам нужны две вещи: форма, которую мы будем вращать, и гвоздь, закрепляющий ее. Учитывая его простоту, мы можем использовать Surface для обоих компонентов — рисование на Canvas тоже было бы прекрасно. Мы можем инкапсулировать составные объекты Panel и Nail в Box с выравниванием TopCenter для размещения гвоздя.

Результат должен выглядеть так:

Чтобы повернуть наш компонуемый Panel, мы должны указать динамический угол. Поскольку мы хотим, чтобы фигура качалась бесконечно, мы можем использовать API перехода с помощью rememberInfiniteTransition . Затем мы обновляем угол, изменяя его значение с начальной точки angleOffset на его конечную точку назначения — я использовал его отрицательный аналог для целей симметрии, но вы можете выбрать иное.

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

Наконец, мы применяем этот угол к Modifier Panel, используя метод rotate. Вот обновленный код Panel:

И его вывод:

Не совсем то, что мы ожидали, верно? Гвоздь не выглядит так, как будто он правильно прикалывает панель. Этому есть простая причина: вращение закреплено в центре панели. Нам нужно переместить его начало в точку привязки: гвоздь.

Смещение источника трансформации

До Compose изменение точки привязки преобразования вращения не представляло большой проблемы. Например, RotateAnimation позволяет изменить точку поворота непосредственно в его конструкторе:

public RotateAnimation (
    float fromDegrees, 
    float toDegrees, 
    float pivotX, 
    float pivotY
)

В Compose метод rotate не позволяет вам изменить свою точку поворота или любые другие, казалось бы, связанные модификаторы. Пока не найдешь: transformOrigin.

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

@Stable
fun Modifier.rotate(degrees: Float) =
    if (degrees != 0f) graphicsLayer(rotationZ = degrees) else this

Он изменяет свойство слоя rotationZ с заданным углом. Это намекает нам на то, что смещение опорной точки может быть вызвано изменением свойства graphicLayer.

Модификатор graphicLayer имеет свойство transformOrigin, которое по умолчанию равно TransformOrigin.Center. Если присмотреться к его реализации, он принимает два атрибута: pivotFractionX и pivotFractionY. Изменив начало координат, мы можем сориентировать его по местоположению нашего гвоздя.

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

Он производит следующий эффект:

Именно то, что мы хотели сделать! Что если элемент уже повернут, как мы могли видеть во вводной анимации.

Сначала нам нужно повернуть наш составной объект Swing:

Обратите внимание, что выравнивание Box изменилось на TopStart.

Мы также скорректировали начало нашего преобразования, потому что мы изменили нашу ссылку, повернув Box.

Это дает следующую анимацию:

Искусство трансформации

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

Повторное открытие нового API иногда может вызывать разочарование. Однако будьте уверены, что команда Compose поможет вам. Если вы чувствуете, что в Compose чего-то не хватает, я бы порекомендовал присоединиться к Kotlin Slack Channel. Участники поддерживают друг друга и способствуют росту сообщества. Для тем, связанных с Compose, существует специальная комната. Я пришел просить о помощи — спасибо Romain Guy за то, что он помог мне найти решение.

Наконец, все вышеперечисленное должно работать с Compose Multiplatform — в этом коде нет ничего специфичного для Android.

Больше статей на подходе! Удачного кодирования!