shikasd
02/28/2020, 2:16 AMDraw
function and transitions currently and have noticed that child composable get recomposed every time transition state changes. Is it possible to avoid child function recomposition?
Example:
val child = @Composable() { println("Hello") }
Transition(definition) { state ->
val x = state[X]
Draw(child) {
canvas.save()
drawChildren()
canvas.restore()
}
}
Sean McQuillan [G]
02/28/2020, 5:37 AM@Composable
private fun RecomposeLots() {
val child = @Composable() { println("Recomposing child") }
var currentTarget by state { 0.1f }
Container {
val animatedFloat = animate(currentTarget) { final ->
currentTarget = final + 1 // keep it animating forever
}
println("Recomposing")
Draw(child) { canvas, parentSize ->
println("Drawing")
canvas.save()
drawChildren()
canvas.restore()
}
}
}
If you swap that inline Draw out for a invocation of a named function composable, you'll get the behavior you want in today's compiler:
@Composable
private fun RecomposeLots() {
val child = @Composable() { println("Recomposing child") }
var currentTarget by state { 0.1f }
Container {
val animatedFloat = animate(currentTarget) { final ->
currentTarget = final + 1 // keep it animating forever
}
println("Recomposing")
DrawButDontRecompose(child)
}
}
@Composable
private fun DrawButDontRecompose(child: @Composable() () -> Unit) {
Draw(child) { canvas, parentSize ->
println("Drawing")
canvas.save()
drawChildren()
canvas.restore()
}
}
Leland Richardson [G]
02/28/2020, 8:34 AMstartNode(DrawNode(onDraw=myDrawCall)
child()
endNode()
So in this case the children executing every time is intentional. For what it’s worth, the draw tag itself just got removed today and the equivalent to what you’re trying to do would be done with a draw modifier. But other composables will be similarly inline, like for example Row and Column will likely be inline soon as well.shikasd
02/28/2020, 12:11 PMDrawModifier
some time ago, but got similar behaviour where children got recomposed. I will try to reproduce it today :)@Composable
fun TestComposable() {
println("Recomposed")
Container(expanded = true, modifier = MyDrawModifier()) {
ColoredRect(color = Color.Black)
}
}
@Composable
fun MyDrawModifier(): DrawModifier {
val currentTarget = animatedFloat(initVal = 0f)
currentTarget.animateTo(1f, anim = TweenBuilder<Float>().apply { this.duration = 1000 })
return remember {
object : DrawModifier {
override fun draw(density: Density, drawContent: () -> Unit, canvas: Canvas, size: PxSize) {
canvas.save()
canvas.translate(0f, size.height.value * currentTarget.value)
drawContent()
canvas.restore()
}
}
}
}
When TestComposable
is added, it is recomposing for each frame 🙂class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
DrawNoInlined {
TestComposable()
}
}
}
}
}
@Composable
fun TestComposable() {
println("Recomposed")
Container(expanded = true) {
ColoredRect(color = Color.Black)
}
}
@Composable
fun MyDrawModifier(): DrawModifier {
val currentTarget = animatedFloat(initVal = 0f)
currentTarget.animateTo(1f, anim = TweenBuilder<Float>().apply { this.duration = 1000 })
return remember {
object : DrawModifier {
override fun draw(density: Density, drawContent: () -> Unit, canvas: Canvas, size: PxSize) {
canvas.save()
canvas.translate(0f, size.height.value * currentTarget.value)
drawContent()
canvas.restore()
}
}
}
}
@Composable
fun DrawNoInlined(f: @Composable() () -> Unit) {
Container(expanded = true, modifier = MyDrawModifier()) {
f()
}
}