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);
}
Note: as with every example on this site, this code is not compiled or run on the page — it is a correct, complete reference you can paste into a real Android Studio project.

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.

scaleTypeVisual effectWhen to use it
centerCropScales 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.
fitCenterScales 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.
centerInsideLike 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.
Quick mental model: centerCrop fills and crops, fitCenter fits and letterboxes, centerInside fits but refuses to upscale.

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);
In real apps, don't hand-roll this every time. A library like Glide or Picasso does exactly this kind of downsampling automatically, plus caching, placeholder handling, and loading from a URL — with a single line such as Glide.with(this).load(recipe.photoUri).into(ivRecipePhoto). We come back to loading images from the network once Retrofit (Java) + Gson is covered later in this track.

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.

Next up: letting the user pick a category from a fixed list, or get suggestions while typing → Spinner & AutoCompleteTextView.