
Круглые кнопки в Android-приложениях улучшают визуальную привлекательность интерфейса и часто используются для выделения ключевых действий – например, кнопки «Добавить» или «Поделиться». В отличие от стандартных прямоугольных элементов, круглые кнопки требуют минимальной настройки через XML-разметку и стили. Основной инструмент здесь – shape drawable, который позволяет задать форму, цвет и тени без сложных кастомных решений.
Для реализации круглой кнопки достаточно трех шагов: создание XML-файла формы, настройка параметров в background и применение стиля к элементу Button или MaterialButton. Важно учитывать, что Material Components (библиотека com.google.android.material:material) предоставляет готовые решения с поддержкой ripple-эффектов и адаптивных теней, но базовый подход работает и с классическим Button.
Пример типичной ошибки – игнорирование атрибута android:padding, из-за чего текст кнопки обрезается или смещается. Также критично задавать одинаковые значения width и height (например, 56dp для Material Design), чтобы кнопка оставалась идеально круглой на всех экранах. Для динамического изменения цвета при нажатии используйте селекторы состояний (state_pressed, state_enabled) в отдельном XML-файле.
Подготовка проекта и выбор нужного макета
Откройте Android Studio и создайте новый проект с шаблоном «Empty Activity». Это минимальная конфигурация, которая не содержит лишних элементов, мешающих работе с пользовательским интерфейсом. В окне создания проекта выберите язык Kotlin (рекомендуется для современной разработки) и минимальный SDK не ниже API 21 (Android 5.0), чтобы обеспечить поддержку большинства устройств.
Перейдите в файл activity_main.xml, расположенный в папке res/layout. Удалите стандартный TextView с текстом «Hello World!», если он присутствует – он не понадобится для реализации круглой кнопки. Вместо него добавьте корневой контейнер ConstraintLayout или FrameLayout, так как они предоставляют гибкость в позиционировании элементов без лишних вложенных структур.
Для круглой кнопки используйте виджет MaterialButton из библиотеки Material Components. Добавьте зависимость в файл build.gradle (Module: app): implementation 'com.google.android.material:material:1.9.0'. Синхронизируйте проект после внесения изменений. Эта библиотека содержит готовые стили и атрибуты, упрощающие создание круглых элементов.
В макете определите кнопку с атрибутом app:shapeAppearanceOverlay="@style/RoundedButton". Создайте стиль в res/values/themes.xml или res/values/styles.xml:
<style name="RoundedButton" parent="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">50%</item>
</style>
Значение 50% делает углы полностью скруглёнными, превращая кнопку в круг.
Разместите кнопку в центре экрана с помощью ограничений в ConstraintLayout. Установите атрибуты app:layout_constraintStart_toStartOf="parent", app:layout_constraintEnd_toEndOf="parent", app:layout_constraintTop_toTopOf="parent" и app:layout_constraintBottom_toBottomOf="parent". Задайте фиксированные размеры кнопки через android:layout_width="64dp" и android:layout_height="64dp" – равные значения гарантируют идеальный круг.
Проверьте совместимость макета на разных экранах. В Android Studio используйте инструмент «Layout Validation» (вкладка в правом верхнем углу редактора макета), чтобы увидеть, как кнопка отображается на устройствах с различными размерами и плотностями пикселей. При необходимости скорректируйте размеры или ограничения.
Для динамического изменения формы кнопки в коде используйте метод setShapeAppearanceModel(). Пример:
val button = findViewById<MaterialButton>(R.id.my_button)
button.shapeAppearanceModel = button.shapeAppearanceModel
.toBuilder()
.setAllCornerSizes(ShapeAppearanceModel.PILL)
.build()
Это полезно, если требуется анимировать переход между круглой и другой формой.
Добавление кнопки в XML-файл разметки
Откройте файл activity_main.xml в папке res/layout. Для круглой кнопки используйте виджет MaterialButton из библиотеки com.google.android.material:material (версия 1.6.0 и выше). Добавьте зависимость в build.gradle модуля, если она отсутствует:
implementation 'com.google.android.material:material:1.11.0'
Вставьте следующий код в XML-файл:
<com.google.android.material.button.MaterialButton
android:id="@+id/roundButton"
android:layout_width="56dp"
android:layout_height="56dp"
android:backgroundTint="#6200EE"
app:cornerRadius="28dp"
app:icon="@drawable/ic_add"
app:iconGravity="textStart"
app:iconTint="#FFFFFF"/>
Параметры cornerRadius задают скругление – значение должно равняться половине ширины/высоты кнопки. Для иконки используйте векторный ресурс из папки res/drawable или PNG-файл.
Атрибуты app:icon и app:iconTint необязательны, но позволяют добавить графический элемент. Если кнопка должна содержать только текст, замените их на android:text="OK" и настройте цвет через android:textColor. Для динамического изменения радиуса в коде используйте:
button.cornerRadius = resources.getDimension(R.dimen.button_radius).toInt()
Проверьте, что родительский контейнер поддерживает MaterialComponents в качестве темы. В файле themes.xml укажите:
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
Без этой настройки стили MaterialButton применяться не будут.
Настройка формы кнопки через атрибуты shape

Добавьте внутрь <shape> блок <solid> для заливки кнопки цветом. Атрибут android:color принимает значения в формате #AARRGGBB или ссылки на ресурсы, например, @color/primary. Для градиента замените <solid> на <gradient> с указанием android:startColor, android:endColor и android:type=»radial».
Контур кнопки настраивается через <stroke>. Укажите ширину линии в android:width=»2dp» и цвет в android:color=»#FF0000″. Для скругления углов (если форма не идеальный круг) используйте <corners> с android:radius=»50dp» – значение должно быть не менее половины высоты кнопки.
Отступы внутри кнопки регулируются атрибутом android:padding в разметке <Button> или через <padding> внутри <shape>. Последний вариант полезен, если нужно задать разные отступы для сторон: android:left=»8dp», android:right=»8dp». Избегайте конфликтов с android:minWidth и android:minHeight в разметке.
Для динамического изменения состояний кнопки (нажато/отпущено) используйте селектор <selector> в отдельном файле drawable. Внутри перечислите элементы <item> с атрибутами android:state_pressed=»true» и ссылками на разные shape-ресурсы. Пример: <item android:drawable=»@drawable/round_button_pressed» android:state_pressed=»true»/>.
Оптимизируйте производительность: избегайте вложенных <shape> и сложных градиентов в списках. Для кнопок с тенями используйте <layer-list> с двумя элементами: нижний – круг с полупрозрачным цветом и смещением, верхний – основной shape. Пример смещения: android:top=»2dp» в <item>.
Применение скругления углов с помощью радиуса

Скругление углов в Android реализуется через атрибут cornerRadius в XML-разметке или программно с помощью метода setCornerRadius() класса GradientDrawable. Минимальное значение радиуса – 0dp (прямые углы), максимальное ограничено высотой или шириной элемента: при превышении половины меньшей стороны углы становятся полностью круглыми. Для кнопки размером 48dp оптимальный радиус скругления – 24dp, что превращает её в круг.
В XML радиус задаётся через тег <corners> внутри <shape>. Пример для кнопки с равномерным скруглением всех углов: <corners android:radius="16dp"/>. Для асимметричного скругления используйте отдельные атрибуты: topLeftRadius, bottomRightRadius и т.д. Значения указываются в dp, чтобы сохранить пропорции на экранах с разной плотностью пикселей.
Программное изменение радиуса требует создания экземпляра GradientDrawable и вызова setCornerRadii() с массивом из 8 значений (по 2 на каждый угол). Пример для скругления только верхних углов: drawable.setCornerRadii(new float[]{16,16, 16,16, 0,0, 0,0});. Этот метод полезен для динамического обновления UI, например, при изменении состояния кнопки.
Для MaterialButton радиус настраивается через атрибут app:cornerRadius или стиль shapeAppearanceOverlay. В отличие от GradientDrawable, здесь радиус применяется ко всем углам одновременно. Пример: app:cornerRadius="8dp". Material Components автоматически обрабатывают тени и отступы, поэтому радиус не должен превышать 50% высоты кнопки, иначе визуальные артефакты неизбежны.
При тестировании скругления проверяйте отображение на устройствах с API 21+ – на старых версиях Android cornerRadius может игнорироваться или работать некорректно. Для совместимости используйте библиотеку AppCompat и избегайте значений радиуса меньше 1dp: на некоторых экранах углы могут выглядеть пикселизированными.
Добавление цвета фона и границ кнопки
Цвет фона и границы кнопки задаются через атрибуты android:background и android:stroke в XML-разметке. Для круглой кнопки используйте shape="oval" в drawable-ресурсе. Пример базовой структуры:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#FF5722"/>
<stroke android:width="2dp" android:color="#3E2723"/>
</shape>
Для динамического изменения цвета в коде используйте метод setBackgroundResource() или setBackgroundColor() с учетом состояний кнопки (нажата, отключена). Пример для программного изменения границы:
GradientDrawable drawable = (GradientDrawable) button.getBackground();
drawable.setStroke(4, Color.parseColor("#4CAF50"));
Таблица рекомендуемых сочетаний цветов фона и границ для разных состояний кнопки:
| Состояние | Цвет фона (HEX) | Цвет границы (HEX) | Ширина границы (dp) |
|---|---|---|---|
| Обычное | #2196F3 | #0D47A1 | 2 |
| Нажатое | #1976D2 | #0D47A1 | 3 |
| Отключенное | #B0BEC5 | #78909C | 1 |
Для анимации изменения цвета границы используйте ValueAnimator с интерполяцией. Пример плавного перехода границы от 2dp к 4dp за 300мс:
ValueAnimator animator = ValueAnimator.ofInt(2, 4);
animator.setDuration(300);
animator.addUpdateListener(animation -> {
GradientDrawable drawable = (GradientDrawable) button.getBackground();
drawable.setStroke((int) animation.getAnimatedValue(), Color.RED);
});
animator.start();
Избегайте использования полупрозрачных цветов для границ – это снижает контрастность на некоторых экранах. Для кнопок с прозрачным фоном задавайте границу минимальной ширины (1dp) и используйте цвета с альфа-каналом не ниже 80%. Пример:
<stroke android:width="1dp" android:color="#8A000000"/>
Для кнопок с градиентным фоном границу задавайте отдельным слоем через <layer-list>. Пример структуры:
<layer-list>
<item>
<shape android:shape="oval">
<gradient android:startColor="#FF9800" android:endColor="#F44336"/>
</shape>
</item>
<item>
<shape android:shape="oval">
<stroke android:width="2dp" android:color="#D32F2F"/>
</shape>
</item>
</layer-list>
Обработка нажатий на круглую кнопку в коде

Для обработки кликов на круглую кнопку используйте стандартный интерфейс View.OnClickListener. В XML-файле разметки добавьте атрибут android:onClick="onRoundButtonClick" к элементу Button или MaterialButton с заданной формой через app:shapeAppearanceOverlay="@style/RoundedButton". В активности реализуйте метод:
public void onRoundButtonClick(View view) { ... }– для XML-обработчика;button.setOnClickListener(v -> { ... })– для программного назначения.
Для динамического изменения состояния кнопки (например, анимации при нажатии) используйте ViewPropertyAnimator или ObjectAnimator. Пример анимации масштабирования:
button.animate() .scaleX(0.95f) .scaleY(0.95f) .setDuration(100) .withEndAction(() -> button.animate().scaleX(1f).scaleY(1f).setDuration(100)) .start();
При работе с MaterialButton учитывайте, что ripple-эффект нажатия автоматически подстраивается под круглую форму. Для кастомизации цвета ripple используйте app:rippleColor="@color/custom_ripple" в XML или button.setRippleColor(ColorStateList.valueOf(Color.RED)) в коде. Если кнопка должна реагировать на долгие нажатия, добавьте View.OnLongClickListener и возвращайте true для предотвращения срабатывания обычного клика.
Проверка отображения кнопки на разных экранах

Круглая кнопка, созданная с помощью shape или MaterialButton, может вести себя непредсказуемо на устройствах с разными плотностями пикселей (dpi) и размерами экранов. Базовые параметры, заданные в dp, масштабируются системой Android, но без дополнительной настройки кнопка рискует выглядеть слишком маленькой на планшетах или растянутой на устройствах с низким разрешением. Например, кнопка с фиксированным размером 56dp на экране с плотностью mdpi (160 dpi) займёт 56 пикселей, а на xxxhdpi (640 dpi) – уже 224 пикселя. Это приводит к визуальному дисбалансу, если не учитывать адаптивность.
Для проверки используйте инструмент Layout Inspector в Android Studio. Он позволяет в реальном времени анализировать, как кнопка отображается на разных экранах, включая её границы, отступы и тени. Запустите приложение на эмуляторе или физическом устройстве с разными характеристиками:
3.7" WVGA (480x800, mdpi)– минимальная плотность, частая проблема с обрезкой краёв;5.5" 1080x1920 (xxhdpi)– стандарт для большинства современных смартфонов;10.1" WXGA (1280x800, mdpi)– планшет, где кнопка может выглядеть потерянной.
Обратите внимание на соотношение размеров кнопки к контейнеру: на экранах с диагональю менее 4 дюймов она не должна занимать более 20% ширины, иначе перекроет другие элементы.
Решение проблем с масштабированием – использование minWidth и minHeight в сочетании с android:inset для MaterialButton. Пример:
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:minHeight="48dp"
app:cornerRadius="24dp"
app:insetLeft="8dp"
app:insetRight="8dp"/>
Для кнопок на основе shape добавьте padding в XML-ресурс формы, чтобы избежать обрезки контента на экранах с низким dpi:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/primary"/>
<size android:width="48dp" android:height="48dp"/>
<padding android:left="4dp" android:right="4dp"/>
</shape>
Тестируйте кнопку с разными шрифтами и локалями. На устройствах с крупными шрифтами (large или huge в настройках доступности) текст внутри кнопки может не помещаться, ломая круглую форму. Решение – динамическое изменение размера текста через autoSizeTextType:
<TextView
android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="10sp"
android:autoSizeMaxTextSize="14sp"
android:autoSizeStepGranularity="1sp"/>
Для языков с длинными словами (например, немецкий) используйте android:ellipsize="end" или сокращайте текст программно.
Не полагайтесь только на эмуляторы. Физические устройства часто демонстрируют артефакты рендеринга, не воспроизводимые в симуляции. Например, на некоторых моделях Samsung с One UI кнопки с тенями (elevation) могут отображаться с двойным обводом из-за особенностей кастомной прошивки. Проверяйте на устройствах с разными версиями Android: от API 21 (Lollipop) до последней, так как поведение MaterialComponents менялось в версиях 1.2.0 и 1.4.0.
Для автоматического тестирования создайте Espresso-тест, проверяющий видимость кнопки на разных экранах. Пример проверки на экране с шириной менее 360dp:
@Test
fun button_isVisibleOnSmallScreen() {
val activityScenario = ActivityScenario.launch(MainActivity::class.java)
onView(withId(R.id.circular_button)).check(matches(isDisplayed()))
activityScenario.onActivity { activity ->
val displayMetrics = activity.resources.displayMetrics
val screenWidthDp = displayMetrics.widthPixels / displayMetrics.density
if (screenWidthDp < 360) {
onView(withId(R.id.circular_button)).check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
}
}
Добавьте аналогичные тесты для высоты экрана и плотности dpi, чтобы покрыть все критические сценарии.
