Реализация Spring-анимаций в Android-приложении (MotionLayout)

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1735 услуг
Реализация Spring-анимаций в Android-приложении (MotionLayout)
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    495

Реализация Spring-анимаций в Android-приложении (MotionLayout)

Android-разработчики долго работали с ValueAnimator и ObjectAnimator + AccelerateDecelerateInterpolator. Spring physics появились официально с Jetpack's SpringAnimation в 2018 году, а MotionLayout в том же году дал декларативный способ описывать сложные анимационные переходы. Сегодня у нас два чётко разделённых инструмента под разные задачи.

SpringAnimation: физика в коде

androidx.dynamicanimation:dynamicanimation — библиотека для spring и fling анимаций отдельных свойств View.

implementation "androidx.dynamicanimation:dynamicanimation:1.0.0"
val springAnim = SpringAnimation(cardView, DynamicAnimation.TRANSLATION_Y).apply {
    spring = SpringForce(0f).apply {  // целевая позиция — 0f (исходная)
        stiffness = SpringForce.STIFFNESS_MEDIUM       // 1500f
        dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY  // 0.75f
    }
}
springAnim.start()

Предустановки Stiffness: STIFFNESS_HIGH (10000), STIFFNESS_MEDIUM (1500), STIFFNESS_LOW (200), STIFFNESS_VERY_LOW (50). DampingRatio: NO_BOUNCY (1.0), LOW_BOUNCY (0.75), MEDIUM_BOUNCY (0.5), HIGH_BOUNCY (0.2).

Для gesture-driven spring — передаём скорость из VelocityTracker:

val vt = VelocityTracker.obtain()
// в onTouchEvent добавляем vt.addMovement(event)
vt.computeCurrentVelocity(1000) // pixels per second
springAnim.setStartVelocity(vt.yVelocity)
springAnim.animateToFinalPosition(targetY)

animateToFinalPosition — удобнее start() при повторных вызовах: если анимация уже идёт, просто меняет целевую позицию без резкого старта заново.

Практический кейс: bottom sheet с drag. Пользователь тянет вниз, отпускает — sheet spring-ится или закрывается в зависимости от скорости и позиции. Логика: если скорость вниз > 1000 dp/s или sheet опущен ниже 40% высоты → анимировать к нижнему краю и dismiss. Иначе → spring back к исходной позиции. Всё через SpringAnimation с setStartVelocity из VelocityTracker.

MotionLayout: декларативные переходы

MotionLayout — подкласс ConstraintLayout, управляет анимацией через MotionScene XML. Идеален для структурных изменений layout (не просто translation/scale, а изменение constraint-ов).

<!-- res/xml/scene_collapsing.xml -->
<MotionScene>
    <ConstraintSet android:id="@+id/start">
        <Constraint android:id="@+id/header"
            android:layout_height="200dp"
            ... />
    </ConstraintSet>
    <ConstraintSet android:id="@+id/end">
        <Constraint android:id="@+id/header"
            android:layout_height="56dp"
            ... />
    </ConstraintSet>
    <Transition
        android:id="@+id/transition"
        motion:constraintSetStart="@+id/start"
        motion:constraintSetEnd="@+id/end"
        motion:duration="400">
        <OnSwipe
            motion:touchAnchorId="@+id/recyclerView"
            motion:touchAnchorSide="top"
            motion:dragDirection="dragUp" />
    </Transition>
</MotionScene>

Spring в MotionLayout — через motion:transitionEasing:

<KeyAttribute
    motion:framePosition="100"
    motion:motionTarget="@+id/fab"
    motion:transitionEasing="overshoot(2.5)">
    <CustomAttribute
        motion:attributeName="scaleX"
        motion:customFloatValue="1.0" />
</KeyAttribute>

overshoot(tension), anticipate(tension), anticipateOvershoot(tension) — встроенные easing функции с пружинным эффектом. Не настоящая физическая модель, но для большинства UI-переходов достаточно.

Для настоящего spring в MotionLayout — KeyCycle с sine wave аппроксимацией пружины. Трудоёмко, зато полный контроль.

Compose: spring() спецификация

В Jetpack Compose spring-анимации — первоклассные граждане:

val offset by animateFloatAsState(
    targetValue = if (isExpanded) 0f else -300f,
    animationSpec = spring(
        dampingRatio = Spring.DampingRatioMediumBouncy,
        stiffness = Spring.StiffnessLow
    )
)

Animatable для gesture-driven:

val animatable = remember { Animatable(0f) }
LaunchedEffect(dragEnd) {
    animatable.animateTo(
        targetValue = 0f,
        animationSpec = spring(stiffness = Spring.StiffnessMedium),
        initialVelocity = lastVelocity
    )
}

initialVelocity в Compose — в единицах значения в секунду. При работе с offset в pixels: velocity из detectDragGestures уже в pixels/second, передаём напрямую.

Сроки

Spring-анимации для 2–4 отдельных UI-элементов через SpringAnimation: 1 день. MotionLayout сцена с gesture-driven переходом (collapsing header, expandable card): 1–2 дня. Полный экран с комплексной анимационной системой: 2–3 дня. Стоимость рассчитывается индивидуально.