Creating a button with an image Android Studio is one of the basic tasks when developing mobile applications, but even experienced developers sometimes encounter nuances. For example, why isn't the image centered inside the button? How to avoid image stretching on different screens? Or why ImageButton behaves differently than a custom button with drawableTop?

In this article we will look at three main ways adding an image to a button: through a standard Button with attributes drawable*, through ImageButton, and through custom ConstraintLayout for complex designs. You will also learn how to optimize images for Android, avoid common mistakes with sizes and ensure correct display on all devices - from Samsung Galaxy S23 Ultra to budget smartphones with a screen 720p.

The material will be useful for beginners who are just both master XML markupand experienced developers looking for ways to improve interface performance. All code examples were tested on the latest versions of Android Studio Giraffe and Android 14 SDK.

1. Method 1: Standard button with drawable attributes*

The easiest way to add an icon to a button is to use a standard element <Button> with attributes drawableLeft, drawableRight, drawableTop or drawableBottom. This method is suitable for most cases when you need to combine text and a small icon (for example, a โ€œBackโ€ button with an arrow or a โ€œShareโ€ button with a social network logo).

Main advantages:

  • ๐Ÿ”น Minimal code - one attribute is enough XML.
  • ๐Ÿ”น Automatic adaptation to size text.
  • ๐Ÿ”น Supports all versions Android (starting from API 1).

Example code for a button with an icon on the left:

<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Send"

android:drawableLeft="@drawable/ic_send"

android:drawablePadding="8dp"

android:padding="12dp"

android:backgroundTint="@color/purple_500"/>

โš ๏ธ Attention: Attribute drawablePadding is responsible for the space between the icon and the text. If you do not specify it, the elements will โ€œstick togetherโ€, especially on small screens.

To prevent the icon from stretching, add a file with a vector image to the folder res/drawable data-i="64">, converted toSVG, converted to Vector Drawable) or use wrap_content for the width of the button. For raster images (PNG) it is recommended to create several versions for different screen densities (mdpi, hdpi, xhdpi etc.).

๐Ÿ’ก

If the icon looks blurry, check that its original resolution is at least 1.5 times the target size on the screen. For example, to display on a 24x24 px screen, the source must be 36x36 px.

2. Method 2: Using ImageButton for buttons without text

ImageButton is a specialized type of button designed to display only an image (without text). It is convenient to use for action icons, for example, โ€œLikeโ€, โ€œCloseโ€ or โ€œSearchโ€ buttons. Unlike the standard button, there is no need to adjust the indents between the text and the image.

Markup example:

<ImageButton

android:layout_width="48dp"

android:layout_height="48dp"

android:src="@drawable/ic_favorite"

android:background="?attr/selectableItemBackgroundBorderless"

android:contentDescription="Add to Favorites"

android:scaleType="centerInside"/>

Key attributes:

  • ๐Ÿ“ scaleType โ€” determines how the image will be scaled. Recommended values: centerInside (preserves proportions) or fitCenter (stretches by width/height).
  • ๐ŸŽจ background โ€” adds a click effect. ?attr/selectableItemBackgroundBorderless for standard animation.
  • ๐Ÿ—ฃ๏ธ contentDescription is a required attribute for accessibility (screen readers).
โš ๏ธ Attention: If you use ImageButton in RecyclerView or ListView, make sure the button size is fixed (for example, 48dp). This will prevent elements from "jumping" when scrolling due to different sizes of images.
๐Ÿ“Š What type of buttons with pictures do you use most often?
Standard Button with drawableLeft/Right
ImageButton
Custom ConstraintLayout
Another option

3. Method 3: Custom button with ConstraintLayout for complex designs

If you need to place an icon and text in a non-standard layout (for example, an icon on top, indented text below), or add additional elements (for example, a badge counter), the best option is to create a custom button based on ConstraintLayout. This method requires more code, but gives full control over the appearance.

Markup example:

<androidx.constraintlayout.widget.ConstraintLayout

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="?attr/selectableItemBackgroundBorderless"

android:padding="12dp">

<ImageView

android:id="@+id/icon"

android:layout_width="24dp"

android:layout_height="24dp"

android:src="@drawable/ic_cart"

app:layout_constraintTop_toTopOf="parent"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintEnd_toEndOf="parent"/>

<TextView

android:id="@+id/label"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Cart"

app:layout_constraintTop_toBottomOf="@id/icon"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

The advantages of this approach:

  • ๐ŸŽ›๏ธ Full control over the positioning of elements.
  • ๐Ÿ–ผ๏ธ Ability to add multiple images or layers (for example, icon + badge).
  • ๐Ÿ“ฑ Easily adapts to different screen sizes using ConstraintLayout.

To do this ConstraintLayout clickable, add to the activity/fragment code:

val customButton = findViewById<ConstraintLayout>(R.id.custom_button)

customButton.setOnClickListener {

// Click processing

}

How to add a badge counter to a custom button?

To add a badge (for example, the number of notifications), place it inside ConstraintLayout is another TextView with a circle background. Example:

<TextView

android:id="@+id/badge"

android:layout_width="20dp"

android:layout_height="20dp"

android:background="@drawable/bg_badge"

android:text="3"

android:textColor="@android:color/white"

android:textSize="12sp"

android:gravity="center"

app:layout_constraintTop_toTopOf="@id/icon"

app:layout_constraintEnd_toEndOf="@id/icon"

app:layout_constraintBottom_toBottomOf="@id/icon"/>

Where bg_badge is a drawable with a round background (for example, red).

4. Optimizing images for buttons

Improperly optimized images can have a significant impact. increase the size APK and slow down the loading of the interface. Here are the key rules for working with graphics in buttons:

Image type Recommended format Optimal size When use
Vector icons Vector Drawable (SVG) Any (scaled) Logos, action icons, simple shapes
Raster icons PNG (with transparency) 24ร—24, 36ร—36, 48ร—48 px Complex icons with shadows or gradients
Background images WebP (with losses) Up to 500ร—500 px Buttons with background image (for example, โ€œBuyโ€ with a photo of the product)

To convert SVG to Vector Drawable:

  1. Place SVG-file in the project folder.
  2. Right-click on folder res/drawable โ†’ New โ†’ Vector Asset.
  3. Select Local file and specify the path to SVG.
  4. Adjust the size (recommended 24dp for icons).
โš ๏ธ Attention: Avoid using JPEG for icons - this format does not support transparency, and the edges of images will look jagged on any background other than white.

โ˜‘๏ธ Checking image optimization

Done: 0 / 5

5. Adaptation to different screen sizes

One of the most common problems when working with buttons and images is their display on screens with different pixel densities (DPIa button that looks perfect on Google Pixel 7 (420 DPImay turn out to be too small). on Samsung Galaxy A10 (270 DPI) or, conversely, huge on a tablet.

Adaptation solutions:

  • ๐Ÿ“ Use dp (density-independent pixels) for all sizes, except background images.
  • ๐Ÿ”„ For raster images, create several versions in folders:
    • drawable-mdpi (160 DPI)
    • drawable-hdpi (240 DPI)
    • drawable-xhdpi (320 DPI)
    • drawable-xxhdpi (480 DPI)
  • ๐Ÿ–ผ๏ธ For background images of buttons, use 9-patch (.9.png) if you need to stretch the image without distortion.

Example of folder structure for an icon ic_like.png:

res/

โ”œโ”€โ”€ drawable-mdpi/

โ”‚ โ””โ”€โ”€ ic_like.png (24ร—24 px)

โ”œโ”€โ”€ drawable-hdpi/

โ”‚ โ””โ”€โ”€ ic_like.png (36ร—36 px)

โ”œโ”€โ”€ drawable-xhdpi/

โ”‚ โ””โ”€โ”€ ic_like.png (48ร—48 px)

โ””โ”€โ”€ drawable-xxhdpi/

โ””โ”€โ”€ ic_like.png (72ร—72 px)

For vector images (Vector Drawable), adaptation occurs automatically, but you can set a fixed size in dp:

<ImageButton

android:layout_width="48dp"

android:layout_height="48dp"

android:src="@drawable/ic_vector_like"

android:scaleType="center"/>

๐Ÿ’ก

Always test the interface on emulators with different screen sizes (for example, Nexus 5X and Pixel XL) before release. Even properly configured buttons may look different on devices with non-standard aspect ratios (for example, 18:9 or 20:9).

6. Dynamically changing images in buttons

Sometimes you need to change the icon of a button programmatically - for example, when pressed (the "Like" button becomes filled) or when the state changes (the "Enable Bluetooth" button shows the current status). To do this, use the methods setImageResource() (for ImageButton) or setCompoundDrawablesWithIntrinsicBounds() (for a standard button).

Example for ImageButton:

val likeButton = findViewById<ImageButton>(R.id.like_button)

var isLiked = false

likeButton.setOnClickListener {

isLiked = !isLiked

val iconRes = if (isLiked) R.drawable.ic_like_filled else R.drawable.ic_like_outline

likeButton.setImageResource(iconRes)

}

For a standard button with text and an icon:

val sendButton = findViewById<Button>(R.id.send_button)

sendButton.setCompoundDrawablesWithIntrinsicBounds(

if (isSent) R.drawable.ic_check else R.drawable.ic_send,

0,

0,

0

)

If you need to animate the icon change (for example, a smooth appearance), use Transition Drawable:

  1. Create file drawable/transition_like.xml:
<transition xmlns:android="http://schemas.android.com/apk/res/android">

<item android:drawable="@drawable/ic_like_outline"/>

<item android:drawable="@drawable/ic_like_filled"/>

</transition>

  1. Apply animation in code:
val transition = likeButton.drawable as TransitionDrawable

transition.startTransition(300) // Duration of animation in ms

Important: When changing images frequently (for example, in RecyclerView) always use libraries like Glide or Picasso for loading and caching to avoid OutOfMemoryError.

7. Common mistakes and how to avoid them

Even experienced developers sometimes make mistakes when working with buttons and images. Here are the most common problems and their solutions:

Problem Cause Solution
The icon is not displayed The path to the resource is incorrect or missing contentDescription for ImageButton. Check the file name in res/drawable and add android:contentDescription.
The button "jumps" when pressed The background with the click effect is missing or the indentation is incorrect. Add android:background="?attr/selectableItemBackground".
Icon stretched Incorrect scaleType or fixed button size. Use android:scaleType="centerInside" i android:adjustViewBounds="true".
Text and icon are not aligned Missing drawablePadding or incorrect gravity/layout_gravity. Add android:drawablePadding="8dp" and configure android:gravity="center_vertical".

Another typical error - ignoring button states (pressed, disabled, focused). To make the button look interactive, create selector in the folder drawable:

<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:state_pressed="true" android:color="@color/purple_200"/>

<item android:state_enabled="false" android:alpha="0.5"/>

<item android:color="@color/purple_500"/>

</selector>

Then apply it to the button:

<Button

...

android:backgroundTint="@drawable/button_selector"/>

โš ๏ธ Attention: On devices with Android 5.0 and below backgroundTint not supported. For them, use android:background s selector, where each item refers to a separate drawable (and not a color).

FAQ: Frequent questions about buttons with pictures

Is it possible to use GIF as a button icon?

Technically yes, but it is highly not recommended. GIF greatly increases the size APK and can cause lags during animation. Instead:

  • For simple animations, use AnimatedVectorDrawable.
  • For complex ones, break the animation into frames and use AnimationDrawable.

Example with AnimatedVectorDrawable:

<ImageButton

android:layout_width="48dp"

android:layout_height="48dp"

android:src="@drawable/avd_like_animation"

android:background="?attr/selectableItemBackgroundBorderless"/>

How to make a round button with an icon?

Use CardView with a radius or create drawable with a circle shape:

  1. Add a constraint implementation 'androidx.cardview:cardview:1.0.0' to build.gradle.
  2. Create markup:
<androidx.cardview.widget.CardView

android:layout_width="56dp"

android:layout_height="56dp"

app:cardCornerRadius="28dp">

<ImageButton

android:layout_width="match_parent"

android:layout_height="match_parent"

android:src="@drawable/ic_plus"

android:background="?attr/selectableItemBackgroundBorderless"/>

</androidx.cardview.widget.CardView>

Why does the button icon look blurry on some devices?

This is due to:

  • Lack of high-density versions of the image (xxhdpi, xxxhdpi).
  • Use of raster images instead of vector ones.
  • Incorrect scaleType (for example, fitXY stretches the image).

Solution:

  1. Convert icons to Vector Drawable.
  2. If the vector is not suitable (for example, for photographs), create versions for everyone DPI.
  3. Use android:scaleType="centerInside".
How to add a shadow to a button with an icon?

For shadows use:

  • For API 21+: android:elevation="4dp" and android:translationZ="2dp".
  • For old versions: create a custom one drawable with a shadow (for example, 9-patch with a gradient).
  • For vector icons: wrap the button in CardView s app:cardElevation.

Example:

<androidx.cardview.widget.CardView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

app:cardElevation="4dp"

app:cardCornerRadius="8dp">

<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Press"

android:drawableLeft="@drawable/ic_button"

android:padding="16dp"/>

</androidx.cardview.widget.CardView>

Is it possible to make a button with animation when held?

Yes, for this use:

  1. GestureDetector to track a long press.
  2. ObjectAnimator for animation (for example, zooming in button).

Code example:

val button = findViewById<ImageButton>(R.id.animated_button)

button.setOnLongClickListener {

val animator = ObjectAnimator.ofPropertyValuesHolder(

button,

PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.2f),

PropertyValuesHolder.ofFloat("scaleY", 1.0f, 1.2f)

)

animator.duration = 300

animator.start()

true // Return true to indicate that the event was processed

}

To reset the animation, add animator.reverse() to OnTouchListener when the button is released.