Как обеспечить, чтобы при анимации кнопок внутри ScrollView остальные элементы корректно перераспределялись?

В коде возникла проблема: анимация сворачивания и раскрытия дочерних кнопок проигрывается, но при этом сдвигаются дочерние кнопки, находящиеся в ScrollView, а этого не должно происходить. Как можно это исправить? <br/> <br/> Внешний вид структуры <br/>
  • 10 апреля 2026 г. 11:02
Ответы на вопрос 2
Проблема в том, что «сдвиг» остальных элементов происходит из‑за изменения layout (виды меняют видимость / высоту / margin) — ScrollView перестраивает дочерние вью, и всё перетасовывается. Решения сводятся к двум подходам: не трогать layout во время анимации, либо выполнять анимацию визуально поверх layout.

Коротко — что сделать:

1) Анимируйте свойства, не влияющие на измерения (translationX/Y, alpha, scale). Такие анимации не вызывают перерасчёт расположения и не сдвинут соседей.
   - Показывать: заранее сделать view.VISIBLE, поставить начальный translationY/alpha и анимировать к нулю/1.
   - Скрывать: анимировать translationY/alpha и в withEndAction() установить visibility = INVISIBLE (а не GONE), если нужно сохранить занимаемое место. Если же ставите GONE — будет перерасчёт и сдвиг.

Пример (Java):
```java
// Показать
view.setVisibility(View.VISIBLE);
view.setAlpha(0f);
view.setTranslationY(30f);
view.animate().alpha(1f).translationY(0f).setDuration(200).start();

// Скрыть (без перерасчёта layout)
view.animate().alpha(0f).translationY(30f).setDuration(200)
    .withEndAction(() -> view.setVisibility(View.INVISIBLE)).start();
```

2) Если нужно, чтобы элемент физически исчезал (GONE) но при этом не было визуального сдвига во время анимации — выполнять анимацию на наложении (ViewGroupOverlay) или в отдельном контейнере поверх ScrollView (FrameLayout над ScrollView). Тогда вы анимируете копию/overlay и в конце проставляете GONE для реального элемента.

3) Убедитесь, что у родителя не включена автоматическая анимация layout (android:animateLayoutChanges="true" или LayoutTransition). Она заставляет родителя плавно перестраивать дочерние и может давать нежелательные сдвиги. Отключите:
```java
((ViewGroup) parent).setLayoutTransition(null);
```

4) Если вы сознательно хотите изменять размеры и чтобы остальные элементы плавно адаптировались — используйте ValueAnimator для анимирования высоты и вызывайте requestLayout() (или TransitionManager.beginDelayedTransition для плавной смены constraint), но это именно перерасчёт layout и элементы будут двигаться.

Резюме:
- Если НЕ нужно, чтобы соседние элементы двигались — анимируйте translation/alpha (или используйте overlay) и не выставляйте GONE во время анимации.
- Если нужно реальное изменение размера/визибилити — тогда придется позволить перерасчёт, либо управлять этим через анимированный overlay/placeholder, чтобы избежать резких сдвигов.
DOScaleY меняет только визуальный масштаб, лейаут-группа его полностью игнорирует. Добавь на buttonChild <code>LayoutElement</code> и твинь <code>preferredHeight</code> вместо скейла — <pre><code>DOTween.To(() =&gt; le.preferredHeight, x =&gt; le.preferredHeight = x, 0f, duration)</code></pre> . Тогда и ребилд нормально пересчитает позиции.
Похожие вопросы