ImageView & ImageButton
Recipes are visual — RecipeBox's whole appeal depends on showing a mouth-watering photo next to every dish. ImageView is the widget for displaying a static or dynamic image, and ImageButton is an ImageView that also behaves like a clickable Button.
ImageView: Displaying an Image
The simplest case sets a drawable resource directly in XML with android:src. RecipeBox's recipe-detail screen shows the recipe's photo at the top of the layout:
<ImageView
android:id="@+id/ivRecipePhoto"
android:layout_width="match_parent"
android:layout_height="220dp"
android:scaleType="centerCrop"
android:contentDescription="Photo of the recipe"
android:src="@drawable/placeholder_recipe" />
Most of the time the actual photo is chosen at runtime — the user picked one from the gallery or camera when creating the recipe, and its location is stored on Recipe.photoUri. Set it from Java with setImageURI(), or use setImageResource() for a bundled drawable:
ImageView ivRecipePhoto = findViewById(R.id.ivRecipePhoto);
if (recipe.photoUri != null) {
ivRecipePhoto.setImageURI(Uri.parse(recipe.photoUri));
} else {
ivRecipePhoto.setImageResource(R.drawable.placeholder_recipe);
}
android:scaleType Reference
scaleType controls how the image is fitted into the ImageView's bounds when the image and the view don't share the same aspect ratio — which is almost always the case with real photos.
| scaleType | Visual effect | When to use it |
|---|---|---|
| centerCrop | Scales the image so it completely fills the view, cropping whatever overflows the edges. No empty space, no distortion. | RecipeBox's recipe photo — a food thumbnail that should fill its box edge-to-edge. |
| fitCenter | Scales the image to fit entirely inside the view (uniformly, no cropping) and centers it. May leave empty space on two sides. | Showing an entire diagram or a photo where cropping would lose important detail. |
| centerInside | Like fitCenter, but never scales the image UP past its original size — only shrinks it down if it's too big. | Small icons or logos that shouldn't be blown up larger than their source resolution. |
ImageButton: A Clickable Image
ImageButton extends ImageView and adds the same click behavior as Button. RecipeBox uses one as a small favorite "heart" icon overlaid on the recipe photo:
<ImageButton
android:id="@+id/ibToggleFavorite"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@android:color/transparent"
android:contentDescription="Toggle favorite"
android:src="@drawable/ic_heart_outline" />
ImageButton ibToggleFavorite = findViewById(R.id.ibToggleFavorite);
ibToggleFavorite.setOnClickListener(v -> {
recipe.isFavorite = !recipe.isFavorite;
int icon = recipe.isFavorite ? R.drawable.ic_heart_filled : R.drawable.ic_heart_outline;
ibToggleFavorite.setImageResource(icon);
favoriteRepository.update(recipe);
});
Loading Large Images Efficiently
A photo taken by a modern phone camera can be many megabytes and several thousand pixels wide — far larger than any ImageView on screen needs. Decoding it at full resolution wastes memory and can even crash the app with an OutOfMemoryError if several recipe photos are in a scrolling list at once.
The classic technique is to first read only the image's dimensions (without allocating the full bitmap), then decode it at a reduced size using BitmapFactory.Options.inSampleSize:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(photoPath, options); // only reads width/height
options.inSampleSize = calculateSampleSize(options, targetWidth, targetHeight);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(photoPath, options); // decodes at reduced size
ivRecipePhoto.setImageBitmap(bitmap);
Content Descriptions for Accessibility
Every ImageView and ImageButton that conveys meaning should carry an android:contentDescription — it's what screen readers like TalkBack announce for users who can't see the image. A purely decorative image (like a background pattern) can instead set android:contentDescription="@null" so TalkBack skips it entirely rather than reading something unhelpful. See Accessibility for the full picture of building accessible screens.