Landscapist

Jetpack Compose image loading library for requesting and displaying images using Glide, Fresco.

94184001-414d4800-fede-11ea-8801-cd0c997024df

Glide

Download

And add a dependency code to your module's build.gradle file.

dependencies {
    implementation "com.github.skydoves:landscapist-glide:1.0.3"
}
Gradle

Usage

We can request and load images simply using a GlideImage composable function.

GlideImage(
  imageModel = imageUrl,
  // Crop, Fit, Inside, FillHeight, FillWidth, None
  contentScale = ContentScale.Crop,
  // shows a placeholder imageAsset when loading.
  placeHolder = imageResource(R.drawable.placeholder),
  // shows an error imageAsset when the request failed.
  error = imageResource(R.drawable.error)
)
Kotlin

RequestOptions and TransitionOptions

We can customize our request options using RequestOptions and TransitionOptions for applying caching strategies, loading transformations.

GlideImage(
  imageModel = poster.poster,
  requestOptions = RequestOptions()
    .override(256, 256)
    .diskCacheStrategy(DiskCacheStrategy.ALL)
    .centerCrop(),
  transitionOptions = BitmapTransitionOptions.withCrossFade(), 
  contentScale = ContentScale.Crop,
  modifier = modifier,
  alignment = Alignment.Center,
  contentScale = ContentScale.Crop,
)
Kotlin

RequestBuilder

Also we can request image by passing a RequestBuilder. RequestBuilder is the backbone of the request in Glide and is responsible for bringing your options together with your requested url or model to start a new load.

GlideImage(
  requestBuilder =
  Glide
    .with(ContextAmbient.current)
    .asBitmap()
    .load(poster.poster)
    .apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL))
    .thumbnail(0.1f)
    .transition(withCrossFade()),
  modifier = Modifier.constrainAs(image) {
    centerHorizontallyTo(parent)
    top.linkTo(parent.top)
  }.aspectRatio(0.8f)
)
Kotlin

94174887-d8ab9e80-fed0-11ea-9f21-a6ed2b899339--1--1

Composable loading, success, failure

We can create our own composable functions following requesting states.

Here is an example that shows a progress indicator when loading an image,

After complete requesting, the indicator will be gone and a content image will be shown.

And if the request failed (e.g. network error, wrong destination), error text will be shown.

 GlideImage(
 imageModel = poster.poster,
 modifier = modifier,
 // shows a progress indicator when loading an image.
 loading = {
   ConstraintLayout(
     modifier = Modifier.fillMaxSize()
   ) {
     val indicator = createRef()
     CircularProgressIndicator(
       modifier = Modifier.constrainAs(indicator) {
         top.linkTo(parent.top)
         bottom.linkTo(parent.bottom)
        start.linkTo(parent.start)
        end.linkTo(parent.end)
       }
     )
   }
 },
 // shows an error text message when request failed.
 failure = {
   Text(text = "image request failed.")
 })
Kotlin

Fresco

Download

And add a dependency code to your module's build.gradle file.

dependencies {
    implementation "com.github.skydoves:landscapist-fresco:<version>"
}
Gradle

Initialize

We should initialize Fresco using ImagePipelineConfig in our Application class.

If we need to fetch images from the network, recommend using OkHttpImagePipelineConfigFactory.

By using an ImagePipelineConfig, we can customize caching, networking, and thread pool strategies.

Here are more references related to the pipeline config.

class App : Application() {

  override fun onCreate() {
    super.onCreate()

    val pipelineConfig =
      OkHttpImagePipelineConfigFactory
        .newBuilder(this, OkHttpClient.Builder().build())
        .setDiskCacheEnabled(true)
        .setDownsampleEnabled(true)
        .setResizeAndRotateEnabledForNetwork(true)
        .build()

    Fresco.initialize(this, pipelineConfig)
  }
}
Kotlin

94174882-d6e1db00-fed0-11ea-86ec-671b5039b1b9

Usage

We can request and load images simply using a FrescoImage composable function.

FrescoImage(
  imageUrl = stringImageUrl,
  // Crop, Fit, Inside, FillHeight, FillWidth, None
  contentScale = ContentScale.Crop,
  // shows a placeholder imageAsset when loading.
  placeHolder = imageResource(R.drawable.placeholder),
  // shows an error imageAsset when the request failed.
  error = imageResource(R.drawable.error)
)
Kotlin

We can customize our requests using an ImageRequest that consists only of a URI, we can use the helper method ImageRequest.fromURI.

val imageRequest = ImageRequestBuilder
  .newBuilderWithSource(uri)
  .setImageDecodeOptions(decodeOptions)
  .setLocalThumbnailPreviewsEnabled(true)
  .setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH)
  .setProgressiveRenderingEnabled(false)
  .setResizeOptions(ResizeOptions(width, height))
  .build()

FrescoImage(
  imageUrl = stringImageUrl,
  imageRequest = imageRequest,
  contentScale = ContentScale.Crop)
Kotlin

94174882-d6e1db00-fed0-11ea-86ec-671b5039b1b9

Composable loading, success, failure

We can create our own composable functions following requesting states.

Here is an example that shows a progress indicator when loading an image,

After complete requesting, the indicator will be gone and a content image will be shown.

And if the request failed (e.g. network error, wrong destination), error text will be shown.

 FrescoImage(
 imageUrl = stringImageUrl,
 modifier = modifier,
 // shows a progress indicator when loading an image.
 loading = {
   ConstraintLayout(
     modifier = Modifier.fillMaxSize()
   ) {
     val indicator = createRef()
     CircularProgressIndicator(
       modifier = Modifier.constrainAs(indicator) {
         top.linkTo(parent.top)
         bottom.linkTo(parent.bottom)
        start.linkTo(parent.start)
        end.linkTo(parent.end)
       }
     )
   }
 },
 // shows an error text message when request failed.
 failure = {
   Text(text = "image request failed.")
 })
Kotlin

Also, we can customize the content image using our own composable function like below.

FrescoImage(
    imageUrl = imageUrl,
    // draw a resized image.
    success = { frescoImageState ->
      frescoImageState.imageAsset?.let {
        Image(
          asset = it,
          modifier = Modifier
            .width(128.dp)
            .height(128.dp))
      }
    },
    loading = { 
      // do something 
    })
Kotlin

Disable lint checking

94366110-cae45c00-0110-11eb-893e-b8a47d45f172

Landscapist uses ExperimentalCoroutinesApi internally.

So if you want to remove the IDE lint checking, add @ExperimentalCoroutinesApi annotation to your function.

And by adding below kotlin options in our build.gradle, we can remove all lint checkings.

kotlinOptions {
    freeCompilerArgs += [
        "-Xallow-jvm-ir-dependencies",
        "-Xskip-prerelease-check",
        "-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi"]
  }
Gradle

GitHub