Custom ImageView using Jetpack Compose

Rilika Uthappa
4 min readJan 15, 2023

--

When developing a large-scale application, it is common to encounter a set of views that require minor modifications but are otherwise repeated. Although the conventional approach involves creating each UI independently in separate files, this can result in unnecessary code duplication. To address this issue, creating custom views is a more efficient solution.

What is a custom view ?

A custom view is a view that you design exactly the way you want by extending the functionality of an existing view and then overwriting everything you deem necessary. It can be a single component such as an image that can be customised in terms of its shape, size, and border, or it can be a widget with several components that are treated as a single view. An example of a widget could be a custom view can be created by combining an image and two text fields to form a widget. Once a particular custom view is created, it can be easily used in multiple places across the app, and even across multiple projects.

Why build custom views in JetPack Compose when we are already familiar with XML? 🤔

Concise : When compared to XML, Compose allows you to accomplish more with less code. This means fewer chances of error 🚩 and easy debugging. As a reviewer or maintainer you have less code to read, comprehend, review and maintain.

Intuitive : There are a number of attributes to consider when creating a custom view in XML and applying a custom style. In Jetpack Compose, we place all UI- related code in the Composable function. If we want to change the background colour, add rounded corners or add a border, we just need to alter code in our composable function.

Accelerate development : Features like live previews, allows to iterate and ship code faster.🚀 Often we need to check a UI component in with a different font size, background color etc. With the ability to create multiple previews we can easily check this without installing the app on our device.

Interoperability: Compose is easily interoperable with XML layouts. This means that you can gradually migrate your existing XML-based layout code to Compose, without having to rewrite everything from scratch. This makes it easier to adopt Compose in existing projects and incrementally benefit from its advantages.

Installation: To kick things off, start by downloading the most recent version of Android Studio, and create an app using the Empty Compose Activity template. The default template already contains some Compose elements.

How to set up Compose for an existing app ?

To start using Compose, add the following dependencies to your app’s build.gradle file.

buildFeatures {
compose true
}

composeOptions {
kotlinCompilerExtensionVersion '1.3.2'
}
dependencies {
implementation 'androidx.activity:activity-compose:1.1.1'
implementation "androidx.compose.ui:ui:1.1.1"
implementation "androidx.compose.ui:ui-tooling-preview:1.1.1"
implementation 'androidx.compose.material:material:1.1.1'

androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.1.1"
debugImplementation "androidx.compose.ui:ui-tooling:1.1.1"
debugImplementation "androidx.compose.ui:ui-test-manifest:1.1.1"
implementation("io.coil-kt:coil-compose:2.0.0-rc01")
}

For Compose Compiler versions that are compatible with your version of Kotlin, check out https://developer.android.com/jetpack/androidx/releases/compose-kotlin

Let’s see how we can build a Custom image component in compose.

Here we build a custom ImageView with custom shape, size and border.

Step 1 : Create a model class with all attributes we need to customize our Image

data class Image(
val width: Int,
val height: Int,
val url: String? = null,
val contentScale: ContentScale? = null
)

Step 2 : Create a composable function with all the required parameters

User Interface in Jetpack Compose is built around composable functions. To create a composable function, @Composable annotation is added to the function name.

To create an image, you need following parameters :

a. Model — To load the image, you need to use ImageRequest Builder.

b. ContentDescription — You need to give a description about the image. You can set it as null.

c. Modifier (Optional) — To change the composable’s size and appearance

  @Composable
fun CustomImageView(image: Image, modifier: Modifier) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(image.url ?: image.drawable),
contentDescription = "Image",
contentScale = image.contentScale,
modifier = modifier
)
}

Step 3 : Call your composable function from the setContent block of your MainActivity

The setContent block defines the activity's layout where composable functions are called.

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CustomImageView(
Image(
drawable = R.drawable.ic_image,
placeHolder = R.drawable.ic_placeholder
), Modifier
.width(100.dp)
.height(100.dp)
.clip(CircleShape)
.border(5.dp)
)
}
}
}

Wrapping up

Custom views help us to encapsulate the visual appearance and behaviour of our reusable views. For groups of views that you know you will use a lot, building a custom view helps prevent repeating code, reduces the likelihood of errors, and makes your code simpler to maintain and modify in the future. Overall, using custom views is an effective method that can speed up the development process and improve code quality in the long run.

--

--