Кнопка с иконкой в Android чаще всего реализуется одним из трёх способов: через ImageButton, через MaterialButton с атрибутом app:icon или через обычный Button с атрибутом android:drawableStart. Выбор зависит от того, нужен ли на кнопке текст, какая библиотека подключена к проекту и как выглядит дизайн-макет.
Ниже разберём каждый вариант с примерами XML и Kotlin, покажем, какие размеры иконок использовать, и разберём типичные ошибки — например, когда иконка не отображается, растягивается или игнорирует цвет из темы.
ImageButton: кнопка-иконка без текста
Если кнопка должна состоять только из иконки (корзина, «поделиться», воспроизведение), подходит ImageButton. Иконка задаётся через android:src, а фон — через android:background.
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_play"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/play" />
Атрибут android:contentDescription обязателен для доступности: без него TalkBack не сможет озвучить назначение кнопки, а Lint выдаст предупреждение. Фон ?attr/selectableItemBackgroundBorderless даёт круглый ripple-эффект при нажатии без видимой рамки.
MaterialButton с атрибутом app:icon
Самый гибкий современный вариант — MaterialButton из библиотеки Material Components. Иконка добавляется атрибутом app:icon, и её можно разместить слева, справа, сверху или снизу относительно текста через app:iconGravity.
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Скачать"
app:icon="@drawable/ic_download"
app:iconGravity="textStart"
app:iconTint="@color/white"
app:iconSize="20dp" />
Чтобы app:icon работал, в проекте должна быть подключена зависимость Material Components и тема приложения должна наследоваться от Theme.MaterialComponents (или её потомка). Иначе атрибут либо не применится, либо приложение упадёт при инфлейте разметки.
⚠️ Внимание: еслиapp:iconигнорируется, первым делом проверьте родительскую тему приложения вthemes.xml. Тема Theme.AppCompat не поддерживает атрибуты MaterialButton — это самая частая причина «пропадающей» иконки.
Обычный Button с drawableStart
Если Material Components в проекте нет и подключать её не хочется, иконку можно пристроить к стандартному Button через android:drawableStart (или устаревший android:drawableLeft).
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Отправить"
android:drawableStart="@drawable/ic_send"
android:drawablePadding="8dp" />
Отступ между иконкой и текстом регулируется android:drawablePadding. У этого способа есть ограничения: размер drawable нельзя задать напрямую в XML, тинт применяется сложнее, а позиционирование ограничено четырьмя сторонами. Программно drawable с нужными границами задаётся так:
val icon = ContextCompat.getDrawable(this, R.drawable.ic_send)
icon?.setBounds(0, 0, icon.intrinsicWidth, icon.intrinsicHeight)
button.setCompoundDrawables(icon, null, null, null)
Сравнение способов
Чтобы выбрать подходящий вариант, удобно свериться с таблицей возможностей каждого подхода.
| Способ | Текст + иконка | Размер иконки в XML | Тинт из темы | Зависимости |
|---|---|---|---|---|
| ImageButton | Нет, только иконка | Да (scaleType) | Через app:tint | Нет |
| MaterialButton + app:icon | Да | Да (app:iconSize) | Да (app:iconTint) | Material Components |
| Button + drawableStart | Да | Нет | Ограниченно | Нет |
| Кастомная View | Да, любая компоновка | Да | Да | Нет |
Размеры и форматы иконок
По гайдлайнам Material Design стандартный размер иконки на кнопке — 18–24 dp, а минимальная область нажатия (touch target) — 48×48 dp. Если визуально иконка меньше, увеличьте область нажатия через android:minWidth/android:minHeight или padding.
Предпочтительный формат — векторный VectorDrawable. PNG придётся готовить в нескольких плотностях (mdpi–xxxhdpi), иначе на части экранов иконка будет размытой.
- 🎨 Иконку создавайте через Vector Asset Studio — там есть встроенная библиотека Material Icons.
- 📐 Держите размер иконки в пределах 18–24 dp относительно текста кнопки.
- 🌈 Цвет задавайте через
app:iconTintили атрибуты темы, а не «зашивайте» в саму иконку.
Программное управление иконкой
Иногда иконку нужно менять динамически — например, переключать «пауза/воспроизведение». Для MaterialButton это делается методом setIcon():
val button = findViewById<MaterialButton>(R.id.playButton)
button.setIconResource(R.drawable.ic_pause)
button.iconTint = ContextCompat.getColorStateList(this, R.color.white)
Для ImageButton используется setImageResource(). Обратите внимание: setIcon() у MaterialButton принимает Drawable, а setIconResource() — id ресурса; путать их не стоит.
☑️ Проверка кнопки с иконкой перед релизом
Типичные проблемы и их решения
Иконка есть в ресурсах, но на кнопке не отображается. Возможные причины: тема не от Material Components, иконка задана через android:icon вместо app:icon (у MaterialButton нужен именно префикс app), либо drawable повреждён.
Иконка чёрная, хотя в макете белая. VectorDrawable по умолчанию использует цвет, зашитый в android:fillColor. Переопределите его через app:iconTint или app:tint, указав цвет из темы — например, ?attr/colorOnPrimary.
⚠️ Внимание: не используйтеandroid:tintиapp:tintодновременно на одной View — поведение на разных версиях Android может отличаться. Для MaterialButton применяйте толькоapp:iconTint.
Иконка растянулась на весь размер кнопки. Такое случается с ImageButton, когда заданы match_parent и не настроен android:scaleType. Установите scaleType="centerInside" или fitCenter, чтобы сохранить пропорции.
Почему drawableStart не тинтуется автоматически
Compound drawables у обычного Button не наследуют цвет текста. Начиная с AppCompat можно использовать app:drawableTint, но поддержка зависит от версии библиотеки. Надёжнее либо перекрасить сам VectorDrawable, либо перейти на MaterialButton, где тинт иконки работает предсказуемо.
FAQ
Как добавить иконку справа от текста на MaterialButton?
Используйте атрибут app:iconGravity="textEnd" или end. Для обычного Button аналог — android:drawableEnd.
Можно ли использовать две иконки на одной кнопке?
Штатно MaterialButton поддерживает одну иконку. Для двух иконок придётся собрать кастомную разметку — например, LinearLayout с двумя ImageView и TextView, оформленный как кнопка.
Почему иконка не видна в превью Android Studio?
Проверьте, что drawable лежит в правильной папке ресурсов и что в превью выбрана тема, наследующаяся от Material Components. Иногда помогает пересборка проекта через Build → Rebuild Project.
Что лучше для иконок: PNG или VectorDrawable?
Векторный формат предпочтительнее: один файл на все плотности экрана, меньший размер APK и простое перекрашивание через тинт. PNG оправдан только для сложной растровой графики.
Как сделать круглую кнопку с иконкой по центру?
Используйте FloatingActionButton с app:srcCompat — это штатный компонент для круглой кнопки-иконки. Либо задайте MaterialButton атрибут app:cornerRadius, равный половине высоты, и app:iconGravity="textStart" без текста.