ImageComponent and ImagePlugin¶
One of the most versatile fatures of Landscapist is the ImageComponent
and ImagePlugin
:
- ImageComponent: The
ImageComponent
is a flexible interface that acts as a container for a collection ofImagePlugins
. - ImagePlugin: The
ImagePlugin
is an executable and pluggable Compose interface, triggered based on specific image states.
With Landscapist, you have the flexibility to compose supported image plugins, or you can even implement your own custom image plugin that will be executed based on the image loading state. This powerful feature empowers you to tailor the image loading behavior according to your specific needs and preferences.
- PainterPlugin: A pinter plugin interface to be composed with the given
Painter
. - LoadingStatePlugin: A pluggable state plugin that will be composed while the state is
ImageLoadState.Loading
. - SuccessStatePlugin: A pluggable state plugin that will be composed when the state is
ImageLoadState.Success
. - FailureStatePlugin: A pluggable state plugin that will be composed when the state is
ImageLoadState.Failure
.
Whether you choose from the existing plugins or create your own, Landscapist offers a seamless and customizable image loading experience for your app.
As an example, you can implement your own LoadingStatePlugin that will be composed specifically while loading an image, as demonstrated below:
data class LoadingPlugin(val source: Any?) : ImagePlugin.LoadingStatePlugin {
// this composable function will be executed while loading an image.
@Composable
override fun compose(
modifier: Modifier,
imageOptions: ImageOptions,
executor: @Composable (IntSize) -> Unit,
): ImagePlugin = apply {
if (source != null && imageOptions != null) {
ImageBySource(
source = source,
modifier = modifier,
alignment = imageOptions.alignment,
contentDescription = imageOptions.contentDescription,
contentScale = imageOptions.contentScale,
colorFilter = imageOptions.colorFilter,
alpha = imageOptions.alpha
)
}
}
}
By creating a custom LoadingStatePlugin
, you can define unique behavior tailored to the loading state of the image. This gives you the freedom to handle loading scenarios in a way that best suits your application's requirements.
Now you can add your own image plugin into the image component like so:
GlideImage(
component = rememberImageComponent {
add(CircularRevealPlugin())
add(LoadingPlugin(source))
},
..
)
CoilImage(
component = rememberImageComponent {
add(CircularRevealPlugin())
add(LoadingPlugin(source))
},
..
)
FrescoImage(
component = rememberImageComponent {
add(CircularRevealPlugin())
add(LoadingPlugin(source))
},
..
)
or you can just add plugins by using the + expression like the below:
GlideImage(
component = rememberImageComponent {
+CircularRevealPlugin()
+LoadingPlugin(source)
},
..
)
CoilImage(
component = rememberImageComponent {
+CircularRevealPlugin()
+LoadingPlugin(source)
},
..
)
FrescoImage(
component = rememberImageComponent {
+CircularRevealPlugin()
+LoadingPlugin(source)
},
..
)
LocalImageComponent¶
You can easily share the same ImageComponent
instance throughout your composable hierarchy by utilizing the imageComponent
extension and LocalImageComponent
, as demonstrated below:
val component = imageComponent {
+CrossfadePlugin()
+PalettePlugin()
}
CompositionLocalProvider(LocalImageComponent provides component) {
val imageComponent = LocalImageComponent.current
GlideImage(
component = imageComponent,
..
)
}
By using LocalImageComponent
, you can ensure that the same ImageComponent
instance is accessible within the entire composable hierarchy, enabling seamless sharing of the image configuration across various composables. This makes it effortless to maintain consistency and manage image handling efficiently throughout your app.