Painter Builder with Coil¶
This guide explains the PainterBuilder utility class from the Fiori Compose library. It shows you how to configure Coil 3 as the ImageLoader used by the library. The PainterBuilder supports both Coil 2 and Coil 3. However, Coil 2 support is deprecated, so you should prefer Coil 3 for new apps.
Summary¶
- The
PainterBuilderclass converts Fiori image/icon abstractions into ComposePainterinstances. - You can work with a variety of resources: local resources, bitmaps, drawables, vector images, files, media URIs, and remote URLs.
- Supports both Coil 2 and Coil 3. Coil 2 paths are retained for backward compatibility, but they are deprecated. To use Coil 3, call the Coil 3 setup near your app's entry point.
Key Functions in PainterBuilder¶
The PainterBuilder companion offers several composable helpers. Here are the most commonly used functions and their purposes:
-
@Composable fun build(icon: FioriIcon, placeholderResId: Int? = null, errorResId: Int? = null): Painter- You can convert a
FioriIconinto a ComposePainter. - The software handles various icon types: RESOURCE, BITMAP, IMAGEVECTOR, PAINTER, DRAWABLE, and URL.
- You can convert a
-
@Composable fun build(image: FioriImage, urlRequestListener: ImageRequest.Listener? = null, placeholderResId: Int? = null, errorResId: Int? = null): Painter- Convert a
FioriImageinto a ComposePainter. - You can handle various image types: RESOURCE, BITMAP, DRAWABLE, URL, and PAINTER.
- URL loading uses Coil and accepts an optional
ImageRequest.Listener. This is used for Coil 2 paths.
- Convert a
-
@Composable fun fetchMediaFileAsPainter(uri: Uri, isVideo: Boolean): Painter- You build a
Painterfrom a media fileUri. - If the file is an image: build a painter from the image.
- If the file is a video, the system builds the painter using the first video frame.
- The
isVideoparameter is specific to Coil 2. In Coil 3, the system automatically detects the media type.
- You build a
-
@Composable fun buildCustomLogo(customLogo: CustomLogo): Painter- You convert a
CustomLogoabstraction into aPainter. - You can handle various image types: RESOURCE, URL, FILE, DRAWABLE, PAINTER.
- You convert a
-
@Composable fun WrappedSubcomposeAsyncImage(...)- This is a wrapper for Coil's
SubcomposeAsyncImagethat supports both Coil 2 and Coil 3. - You can provide
loading,onSuccess, andonErrorcomposables or handlers. The system internally selects either the Coil 2 or Coil 3 API based on whether the Coil 3 factory is available.
- This is a wrapper for Coil's
ImageLoader Setup Helpers (Static APIs)¶
-
setupCoil3ImageLoader(imageLoaderFactory: () -> coil3.ImageLoader)- Create a factory that returns a Coil 3
ImageLoadersingleton. ThePainterBuildercalls this factory whenever it needs the Coil 3 image loader. - The factory returns a singleton instance each time you call it.
- Create a factory that returns a Coil 3
-
@Deprecated setupImageLoader(context: Context, okHttpClient: OkHttpClient, isCacheEnabled: Boolean = true, memoryCachePercent: Double = 0.2)- This deprecated helper installs a custom Coil 2
ImageLoaderglobally. It uses the Coil API and an internalFioriImageLoaderFactory. - This feature is kept for backward compatibility.
- This deprecated helper installs a custom Coil 2
-
@Deprecated setupCoil2ImageLoader(imageLoader: ImageLoader)- Deprecated: directly setting a custom Coil 2
ImageLoaderinstance.
- Deprecated: directly setting a custom Coil 2
How PainterBuilder Chooses Coil 2 vs Coil 3¶
- If you call
PainterBuilder.setupCoil3ImageLoader { ... }and the provided factory returns a Coil 3 singleton image loader,PainterBuilderuses Coil 3 APIs for URL, file, and media loading. It also usesSubcomposeAsyncImage. - If you don't provide a Coil 3 factory,
PainterBuilderuses Coil 2 APIs, which are on a deprecated path. This ensures older apps continue to work without changes. However, you should migrate to Coil 3 as soon as possible.
Example: Setting up Coil 3¶
Place the Coil 3 setup near your app entry point, such as the root composable or Application. The demo app sets up a singleton Coil 3 ImageLoader factory using Compose's platform utilities. It then passes the singleton to PainterBuilder.
@Composable
private fun SetupCoil3() {
// 1) Provide a Compose-level singleton ImageLoader factory used by Coil 3 Compose integration
coil3.compose.setSingletonImageLoaderFactory { context ->
coil3.ImageLoader.Builder(context)
.crossfade(true)
.components {
// Optional: add custom fetchers/decoders, e.g. OkHttp network fetcher
add(OkHttpNetworkFetcherFactory(callFactory = { OkHttpClient() }))
// Use AnimatedImageDecoder on API 28+ for animated images, otherwise fallback to GifDecoder
if (android.os.Build.VERSION.SDK_INT >= 28) {
add(AnimatedImageDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
// Add SVG and video decoders if you need them
add(SvgDecoder.Factory())
add(VideoFrameDecoder.Factory())
}
.build()
}
// 2) Supply the same Coil 3 singleton ImageLoader to Fiori Compose PainterBuilder
val context = coil3.compose.LocalPlatformContext.current
PainterBuilder.setupCoil3ImageLoader {
// Return the singleton coil3 ImageLoader. The factory must return a singleton when called multiple times.
coil3.SingletonImageLoader.get(context)
}
}
Notes:
- Call
SetupCoil3()from your root composable. This ensures that theImageLoaderandPainterBuilderare ready before any image loading occurs. - The
setSingletonImageLoaderFactoryfunction serves as a Coil 3 helper. It registers a factory forImageLoaderthat is aware of Compose.
Minimal Migration Notes (Coil 2 -> Coil 3)¶
PainterBuilderalready supports both. You should callsetupCoil3ImageLoaderat app startup.- When you configure Coil 3,
PainterBuilderuses Coil 3 APIs and decoders:SvgDecoder,VideoFrameDecoder, andAnimatedImageDecoder/GifDecoder. - If you used
PainterBuilder.setupImageLoaderin Coil 2, you can remove that call. Replace it with the Coil 3 setup shown above.
Edge Cases & Tips¶
- Make sure you register the Coil 3 factory early in the root composable. This ensures that components using images at startup don't revert to the deprecated Coil 2.
- Provide a singleton
ImageLoader. Creating manyImageLoaderinstances wastes memory and resources. - When you load video frames, make sure you add
VideoFrameDecoder.Factory()to theImageLoadercomponents. - To enable SVG support, add
SvgDecoder.Factory()to theImageLoadercomponents. Both Coil 2 and Coil 3 paths include SVG decoders where needed.
External References¶
For more details on Coil 3 and its Compose integration, refer to the official documentation and API pages.