Программирование

Как убрать прямые углы при переходе между активити

В Android прямые углы при переходе между активити возникают из clipToOutline. Используйте clipToOutline и clipChildren, чтобы обрезать контент по RoundedCorner.

Как обычно решают разработчики проблему с прямыми углами, когда переходят между активити в лаунчере? Если замедлить смену активити, можно заметить, что в месте скругления внутренние блоки, которые находятся выше угла, накладываются, и появляется прямой угол. Какие практики можно применить, чтобы это исправить? И есть ли в Android что‑то вроде CSS‑свойства overflow: hidden?

Краткий ответ
Разработчики обычно применяют clipToOutline (или clipChildren + собственный OutlineProvider) для корневой вью‑страницы, чтобы «обрезать» её по форме RoundedCorner, которую задали в windowBackground. Внутренние блоки, которые находятся над скруглением, делают фон той же формы, либо добавляют отступы, чтобы они не «выходили» за скругленный край. В качестве аналога CSS‑свойства overflow: hidden в Android служат атрибуты android:clipToOutline="true" и android:clipChildren="true".


Содержание


Как работает автоматическое скругление в лаунчере

Лаунчер Android использует RoundedCorner API и свойства окна (windowBackground), чтобы автоматически обрезать каждую активити под скругленные углы устройства. При переходе между активити система применяет маску, которая скрывает содержимое за скруглением. Если clipToOutline не включён, внутренние элементы могут «выходить» за пределы скругления, создавая прямой угол.

Согласно документации Android, система применяет RoundedCorner к DecorView окна, но только если clipToOutline=true. [Android Developers]


Практики для корректного обрезания активити

1. Использование clipToOutline и OutlineProvider

  • В styles.xml задайте для окна скругление:
    xml
    <item name="android:windowBackground">@drawable/rounded_window</item>
    <item name="android:clipToOutline">true</item>
    
  • В rounded_window.xml определите shape с нужным cornerRadius.
  • Для более гибкого скругления можно создать собственный ViewOutlineProvider:
    kotlin
    class RoundedCornerProvider(private val radius: Float) : ViewOutlineProvider() {
        override fun getOutline(view: View, outline: Outline) {
            outline.setRoundRect(0, 0, view.width, view.height, radius)
        }
    }
    
    // В Activity
    val root = findViewById<View>(android.R.id.content)
    root.clipToOutline = true
    root.outlineProvider = RoundedCornerProvider(16.dp)
    
    Это гарантирует, что весь контент окна будет обрезан по заданной форме.

Пример реализации можно увидеть в ответе на StackOverflow: ClipToOutline with cornerRadii with background [StackOverflow]

2. Применение Material Shape Appearance

Material Components позволяют задать форму окна через ShapeAppearanceOverlay.

xml
<item name="android:background">@drawable/rounded_material</item>
<item name="android:clipToOutline">true</item>
xml
<!-- rounded_material.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <solid android:color="@color/background"/>
    <corners android:radius="16dp"/>
</shape>

Если нужны разные радиусы для разных углов, используйте android:radiusX и android:radiusY для каждого угла (доступно в API 29+).

Для подробностей обратитесь к материалам от Google: Material Shape Appearance [Android Developers]

3. Работа с фоном и внутренними элементами

  • Фон: Внутренние блоки, которые находятся над скруглением, делают фон той же формы, либо добавляют отступы, чтобы они не «выходили» за скругленный край.
  • Отступы: Добавьте padding к корневой вью (например, 16dp), чтобы элементы не прилегали к скругленному углу.
  • Плавные границы: Если часть UI должна быть прозрачной в скругленном углу, используйте ViewOutlineProvider с setConvexPath, чтобы задать произвольный путь.

Как решить задачу «только верхние углы», можно посмотреть на ответ Android: how to clip only top rounded corners [StackOverflow]

4. Управление переходами между активити

  • Переходы: При использовании ActivityOptions.makeSceneTransitionAnimation() система автоматически применяет маску. Если видите прямой угол, проверьте, что в обоих активити clipToOutline=true.
  • Плавность: Уменьшайте время анимации, чтобы не заметить «выход» элементов.
  • Оптимизируйте: Если переходы всё равно вызывают визуальные артефакты, добавьте android:windowDisablePreview=true в манифесте, чтобы система не показывала превью старой активити.

Пример того, как переходы влияют на скругление, можно найти в вопросе How to add rounded corners and a mask to the interface using Transition in Compose Navigation [StackOverflow]


Аналог CSS‑свойства overflow: hidden в Android

В Android аналогом является комбинация android:clipToOutline="true" и android:clipChildren="true".

  • clipToOutline обрезает содержимое вью по форме, заданной OutlineProvider или background с shape.
  • clipChildren заставляет родительскую вью обрезать дочерние элементы, если они выходят за границы родителя.

Подробнее о работе clipChildren можно узнать в официальной документации Android: View#clipChildren [Android Developers]


Заключение

  • Включите clipToOutline для корневой вью и задайте OutlineProvider с нужным радиусом.
  • Используйте Material Shape Appearance, чтобы задать форму окна и согласовать фон внутренних блоков.
  • Добавляйте отступы и, при необходимости, маски для конкретных углов.
  • Проверьте переходы и убедитесь, что обе активити используют одинаковую обрезку.
  • Аналог overflow: hidden реализуется через clipToOutline и clipChildren.

Следуя этим практикам, вы устраните появление прямого угла при переходах между активити в лаунчере и получите плавный, эстетически корректный интерфейс.


Источники

  1. ClipToOutline with cornerRadii with background – StackOverflow
  2. ClipToOutline and CornerRadii – StackOverflow
  3. Android round corner layout in dialogfragment – StackOverflow
  4. How to make layout with rounded corners? – StackOverflow
  5. RoundedCorner API reference – Android Developers
  6. Material Shape Appearance – Android Developers
  7. View#clipChildren – Android Developers
Авторы
Проверено модерацией
Модерация