CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-compose-components--components

Additional UI components for Compose Multiplatform including SplitPane layouts, resource loading, animated images, and UI tooling preview support

Pending
Overview
Eval results
Files

animatedimage.mddocs/

Animated Images

Cross-platform animated image support with automatic format detection and platform-optimized loading for GIFs and other animated formats, providing seamless animation playback in Compose applications.

Capabilities

AnimatedImage Type

Core animated image type with platform-specific implementations.

/**
 * Platform-specific animated image representation
 * Handles frame-based animations with proper timing and looping
 */
expect class AnimatedImage

Platform Notes:

  • Desktop: Uses Skia Codec for efficient frame-based animation
  • Other platforms: Platform-specific implementations for optimal performance

Image Loading Functions

Load animated images from various sources with automatic format detection.

/**
 * Load an animated image from a path (network URL or local file)
 * Automatically detects if the path is a network URL or local file path
 * @param path URL or file path to the animated image
 * @return AnimatedImage instance ready for animation
 */
expect suspend fun loadAnimatedImage(path: String): AnimatedImage

/**
 * Load an animated image from application resources
 * @param path Resource path within the application bundle
 * @return AnimatedImage instance ready for animation
 */
expect suspend fun loadResourceAnimatedImage(path: String): AnimatedImage

Usage Examples:

import org.jetbrains.compose.animatedimage.*

@Composable
fun AnimatedImageDemo() {
    var animatedImage by remember { mutableStateOf<AnimatedImage?>(null) }
    
    // Load from network
    LaunchedEffect(Unit) {
        animatedImage = loadAnimatedImage("https://example.com/animation.gif")
    }
    
    // Load from resources
    LaunchedEffect(Unit) {
        animatedImage = loadResourceAnimatedImage("animations/spinner.gif")
    }
    
    animatedImage?.let { image ->
        Image(
            bitmap = image.animate(),
            contentDescription = "Animated GIF",
            modifier = Modifier.size(200.dp)
        )
    }
}

Animation Playback

Convert animated images to displayable bitmaps with automatic frame progression.

/**
 * Animate the loaded image, returning the current frame as ImageBitmap
 * Handles frame timing and looping automatically
 * @return Current frame as ImageBitmap for display in Image composable
 */
@Composable
expect fun AnimatedImage.animate(): ImageBitmap

Usage Examples:

@Composable
fun LoadingSpinner() {
    var spinner by remember { mutableStateOf<AnimatedImage?>(null) }
    
    LaunchedEffect(Unit) {
        spinner = loadResourceAnimatedImage("loading-spinner.gif")
    }
    
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        spinner?.let { 
            Image(
                bitmap = it.animate(), // Automatically progresses through frames
                contentDescription = "Loading...",
                modifier = Modifier.size(48.dp)
            )
        } ?: CircularProgressIndicator() // Fallback while loading
    }
}

Utility Extensions

Additional utilities for working with animated images.

/**
 * A blank 1x1 pixel ImageBitmap for placeholder usage
 */
val ImageBitmap.Companion.Blank: ImageBitmap

Usage Examples:

@Composable
fun AnimatedImageWithPlaceholder(imageUrl: String) {
    var animatedImage by remember { mutableStateOf<AnimatedImage?>(null) }
    var isLoading by remember { mutableStateOf(true) }
    
    LaunchedEffect(imageUrl) {
        isLoading = true
        try {
            animatedImage = loadAnimatedImage(imageUrl)
        } catch (e: Exception) {
            // Handle loading error
        } finally {
            isLoading = false
        }
    }
    
    Image(
        bitmap = when {
            isLoading -> ImageBitmap.Blank
            animatedImage != null -> animatedImage!!.animate()
            else -> ImageBitmap.Blank // Error state
        },
        contentDescription = "Animated image",
        modifier = Modifier.size(150.dp)
    )
}

Advanced Usage Patterns

Conditional Animation

@Composable
fun ConditionalAnimation(shouldAnimate: Boolean) {
    var animatedImage by remember { mutableStateOf<AnimatedImage?>(null) }
    var staticImage by remember { mutableStateOf<ImageBitmap?>(null) }
    
    LaunchedEffect(Unit) {
        animatedImage = loadAnimatedImage("animation.gif")
        staticImage = loadAnimatedImage("static-frame.png").animate()
    }
    
    Image(
        bitmap = if (shouldAnimate) {
            animatedImage?.animate() ?: ImageBitmap.Blank
        } else {
            staticImage ?: ImageBitmap.Blank
        },
        contentDescription = "Conditional animation",
        modifier = Modifier.size(100.dp)
    )
}

Animation Gallery

@Composable
fun AnimationGallery() {
    val animationUrls = listOf(
        "https://example.com/cat.gif",
        "https://example.com/dog.gif", 
        "https://example.com/bird.gif"
    )
    
    LazyRow {
        items(animationUrls) { url ->
            AnimatedImageCard(url)
        }
    }
}

@Composable
fun AnimatedImageCard(url: String) {
    var animatedImage by remember { mutableStateOf<AnimatedImage?>(null) }
    
    Card(
        modifier = Modifier
            .size(120.dp)
            .padding(8.dp)
    ) {
        LaunchedEffect(url) {
            animatedImage = loadAnimatedImage(url)
        }
        
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            animatedImage?.let { image ->
                Image(
                    bitmap = image.animate(),
                    contentDescription = null,
                    modifier = Modifier.fillMaxSize(),
                    contentScale = ContentScale.Crop
                )
            } ?: CircularProgressIndicator(modifier = Modifier.size(24.dp))
        }
    }
}

Error Handling

@Composable
fun RobustAnimatedImage(imagePath: String) {
    var animatedImage by remember { mutableStateOf<AnimatedImage?>(null) }
    var error by remember { mutableStateOf<String?>(null) }
    var isLoading by remember { mutableStateOf(true) }
    
    LaunchedEffect(imagePath) {
        isLoading = true
        error = null
        try {
            animatedImage = loadAnimatedImage(imagePath)
        } catch (e: Exception) {
            error = "Failed to load animation: ${e.message}"
            animatedImage = null
        } finally {
            isLoading = false
        }
    }
    
    Box(
        modifier = Modifier.size(200.dp),
        contentAlignment = Alignment.Center
    ) {
        when {
            isLoading -> CircularProgressIndicator()
            error != null -> Text(
                error!!,
                color = MaterialTheme.colors.error,
                textAlign = TextAlign.Center
            )
            animatedImage != null -> Image(
                bitmap = animatedImage!!.animate(),
                contentDescription = "Animation",
                modifier = Modifier.fillMaxSize()
            )
            else -> Text("No image")
        }
    }
}

Performance Considerations

  • Automatic Format Detection: The system automatically detects image formats and optimizes loading
  • Frame Timing: Animation respects original frame timing for smooth playback
  • Memory Management: Platform-specific implementations optimize memory usage
  • Network Loading: Supports both local and network image sources seamlessly
  • Infinite Looping: Animations loop continuously without manual intervention

Platform Implementation Details

Desktop Implementation

  • Uses Skia Codec for efficient frame decoding
  • Supports GIF, WebP, and other animated formats
  • Automatic network URL detection
  • Loaders: NetworkAnimatedImageLoader, LocalAnimatedImageLoader, ResourceAnimatedImageLoader

Multiplatform Support

  • Each platform provides optimized implementations
  • Consistent API across all supported platforms
  • Platform-specific performance optimizations

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-compose-components--components

docs

animatedimage.md

index.md

preview.md

resources.md

splitpane.md

tile.json