JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
16.27k stars 1.18k forks source link

ImageComposeScene. get rid of necessity to warm up animations, calling initial `render`'s #1395

Closed igordmn closed 1 month ago

igordmn commented 3 years ago

Compose 1.0.0-beta5

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.ui.ImageComposeScene
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toComposeImageBitmap
import androidx.compose.ui.window.singleWindowApplication
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.ExperimentalTime

@OptIn(ExperimentalTime::class, androidx.compose.ui.ExperimentalComposeUiApi::class)
fun main() {
    val scene = ImageComposeScene(100, 100) {
        Box(Modifier.fillMaxSize().background(Color.White)) {
            CircularProgressIndicator()
        }
    }
    scene.render() // start animation

    val f0 = scene.render(milliseconds(0L)).toComposeImageBitmap()
    val f100 = scene.render(milliseconds(100L)).toComposeImageBitmap()
    val f200 = scene.render(milliseconds(200L)).toComposeImageBitmap()
    val f300 = scene.render(milliseconds(300L)).toComposeImageBitmap()
    val f400 = scene.render(milliseconds(400L)).toComposeImageBitmap()
    val f500 = scene.render(milliseconds(500L)).toComposeImageBitmap()

    singleWindowApplication {
        Row {
            Image(f0, "image")
            Image(f100, "image")
            Image(f200, "image")
            Image(f300, "image")
            Image(f400, "image")
            Image(f500, "image")
        }
    }
}

Here we call scene.render() to warm up the animation.

It is not obvious for the users of ImageComposeScene, as all they want is to get the image at the virtual 500ms. If we call scene.render(milliseconds(500L)) without warming up - we get the first frame.

We can probably perform multiple recompositions in the single render call to fix that.

Or warm up animations implicitly, in ImageComposeScene constructor (or in setContent). But it doesn't fix cases, when we use some if (isVisible) condition inside content, which we set to true manually.

okushnikov commented 2 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.