Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09cfb449 authored by Andreas Miko's avatar Andreas Miko Committed by Android (Google) Code Review
Browse files

Merge "Add new PropertyTransformation DrawScale" into main

parents 61db854a 3df36b77
Loading
Loading
Loading
Loading
+50 −1
Original line number Diff line number Diff line
@@ -33,7 +33,9 @@ import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.isSpecified
import androidx.compose.ui.geometry.isUnspecified
import androidx.compose.ui.geometry.lerp
import androidx.compose.ui.graphics.drawscope.scale
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.IntermediateMeasureScope
import androidx.compose.ui.layout.Measurable
@@ -85,6 +87,9 @@ internal class Element(val key: ElementKey) {
        /** The size of this element. */
        var size = SizeUnspecified

        /** The draw scale of this element. */
        var drawScale = Scale.Default

        /** The alpha of this element. */
        var alpha = AlphaUnspecified
    }
@@ -110,6 +115,13 @@ internal class Element(val key: ElementKey) {
    }
}

data class Scale(val scaleX: Float, val scaleY: Float, val pivot: Offset = Offset.Unspecified) {

    companion object {
        val Default = Scale(1f, 1f, Offset.Unspecified)
    }
}

/** The implementation of [SceneScope.element]. */
@OptIn(ExperimentalComposeUiApi::class)
internal fun Modifier.element(
@@ -160,9 +172,24 @@ internal fun Modifier.element(
        }
    }

    val drawScale by
        remember(layoutImpl, element, scene, sceneValues) {
            derivedStateOf { getDrawScale(layoutImpl, element, scene, sceneValues) }
        }

    drawWithContent {
            if (shouldDrawElement(layoutImpl, scene, element)) {
                drawContent()
                if (drawScale == Scale.Default) {
                    this@drawWithContent.drawContent()
                } else {
                    scale(
                        drawScale.scaleX,
                        drawScale.scaleY,
                        if (drawScale.pivot.isUnspecified) center else drawScale.pivot
                    ) {
                        this@drawWithContent.drawContent()
                    }
                }
            }
        }
        .modifierTransformations(layoutImpl, scene, element, sceneValues)
@@ -377,6 +404,28 @@ private fun IntermediateMeasureScope.measure(
    return placeable
}

private fun getDrawScale(
    layoutImpl: SceneTransitionLayoutImpl,
    element: Element,
    scene: Scene,
    sceneValues: Element.TargetValues
): Scale {
    return computeValue(
        layoutImpl,
        scene,
        element,
        sceneValue = { Scale.Default },
        transformation = { it.drawScale },
        idleValue = Scale.Default,
        currentValue = { Scale.Default },
        lastValue = {
            sceneValues.lastValues.drawScale.takeIf { it != Scale.Default }
                ?: element.lastSharedValues.drawScale
        },
        ::lerp,
    )
}

@OptIn(ExperimentalComposeUiApi::class)
private fun IntermediateMeasureScope.place(
    layoutImpl: SceneTransitionLayoutImpl,
+8 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastMap
import com.android.compose.animation.scene.transformation.AnchoredSize
import com.android.compose.animation.scene.transformation.AnchoredTranslate
import com.android.compose.animation.scene.transformation.DrawScale
import com.android.compose.animation.scene.transformation.EdgeTranslate
import com.android.compose.animation.scene.transformation.Fade
import com.android.compose.animation.scene.transformation.ModifierTransformation
@@ -126,6 +127,7 @@ data class TransitionSpec(
        val modifier = mutableListOf<ModifierTransformation>()
        var offset: PropertyTransformation<Offset>? = null
        var size: PropertyTransformation<IntSize>? = null
        var drawScale: PropertyTransformation<Scale>? = null
        var alpha: PropertyTransformation<Float>? = null

        fun <T> onPropertyTransformation(
@@ -144,6 +146,10 @@ data class TransitionSpec(
                    throwIfNotNull(size, element, name = "size")
                    size = root as PropertyTransformation<IntSize>
                }
                is DrawScale -> {
                    throwIfNotNull(drawScale, element, name = "drawScale")
                    drawScale = root as PropertyTransformation<Scale>
                }
                is Fade -> {
                    throwIfNotNull(alpha, element, name = "alpha")
                    alpha = root as PropertyTransformation<Float>
@@ -167,7 +173,7 @@ data class TransitionSpec(
            }
        }

        return ElementTransformations(shared, modifier, offset, size, alpha)
        return ElementTransformations(shared, modifier, offset, size, drawScale, alpha)
    }

    private fun throwIfNotNull(
@@ -187,5 +193,6 @@ internal class ElementTransformations(
    val modifier: List<ModifierTransformation>,
    val offset: PropertyTransformation<Offset>?,
    val size: PropertyTransformation<IntSize>?,
    val drawScale: PropertyTransformation<Scale>?,
    val alpha: PropertyTransformation<Float>?,
)
+13 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.compose.animation.scene

import androidx.compose.animation.core.AnimationSpec
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
@@ -224,11 +225,21 @@ interface PropertyTransformationBuilder {
    /**
     * Scale the [width] and [height] of the element(s) matching [matcher]. Note that this scaling
     * is done during layout, so it will potentially impact the size and position of other elements.
     *
     * TODO(b/290184746): Also provide a scaleDrawing() to scale an element at drawing time.
     */
    fun scaleSize(matcher: ElementMatcher, width: Float = 1f, height: Float = 1f)

    /**
     * Scale the drawing with [scaleX] and [scaleY] of the element(s) matching [matcher]. Note this
     * will only scale the draw inside of an element, therefore it won't impact layout of elements
     * around it.
     */
    fun scaleDraw(
        matcher: ElementMatcher,
        scaleX: Float = 1f,
        scaleY: Float = 1f,
        pivot: Offset = Offset.Unspecified
    )

    /**
     * Scale the element(s) matching [matcher] so that it grows/shrinks to the same size as [anchor]
     * .
+6 −0
Original line number Diff line number Diff line
@@ -21,10 +21,12 @@ import androidx.compose.animation.core.DurationBasedAnimationSpec
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.spring
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import com.android.compose.animation.scene.transformation.AnchoredSize
import com.android.compose.animation.scene.transformation.AnchoredTranslate
import com.android.compose.animation.scene.transformation.DrawScale
import com.android.compose.animation.scene.transformation.EdgeTranslate
import com.android.compose.animation.scene.transformation.Fade
import com.android.compose.animation.scene.transformation.PropertyTransformation
@@ -178,6 +180,10 @@ internal class TransitionBuilderImpl : TransitionBuilder {
        transformation(ScaleSize(matcher, width, height))
    }

    override fun scaleDraw(matcher: ElementMatcher, scaleX: Float, scaleY: Float, pivot: Offset) {
        transformation(DrawScale(matcher, scaleX, scaleY, pivot))
    }

    override fun anchoredSize(matcher: ElementMatcher, anchor: ElementKey) {
        transformation(AnchoredSize(matcher, anchor))
    }
+48 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.compose.animation.scene.transformation

import androidx.compose.ui.geometry.Offset
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.Scale
import com.android.compose.animation.scene.Scene
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState

/**
 * Scales the draw size of an element. Note this will only scale the draw inside of an element,
 * therefore it won't impact layout of elements around it.
 */
internal class DrawScale(
    override val matcher: ElementMatcher,
    private val scaleX: Float,
    private val scaleY: Float,
    private val pivot: Offset = Offset.Unspecified,
) : PropertyTransformation<Scale> {

    override fun transform(
        layoutImpl: SceneTransitionLayoutImpl,
        scene: Scene,
        element: Element,
        sceneValues: Element.TargetValues,
        transition: TransitionState.Transition,
        value: Scale,
    ): Scale {
        return Scale(scaleX, scaleY, pivot)
    }
}
Loading