1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.compose.animation.scene.transformation 18 19 import androidx.compose.ui.unit.IntSize 20 import com.android.compose.animation.scene.Element 21 import com.android.compose.animation.scene.ElementKey 22 import com.android.compose.animation.scene.ElementMatcher 23 import com.android.compose.animation.scene.SceneKey 24 import com.android.compose.animation.scene.SceneTransitionLayoutImpl 25 import com.android.compose.animation.scene.TransitionState 26 27 /** Anchor the size of an element to the size of another element. */ 28 internal class AnchoredSize( 29 override val matcher: ElementMatcher, 30 private val anchor: ElementKey, 31 private val anchorWidth: Boolean, 32 private val anchorHeight: Boolean, 33 ) : PropertyTransformation<IntSize> { transformnull34 override fun transform( 35 layoutImpl: SceneTransitionLayoutImpl, 36 scene: SceneKey, 37 element: Element, 38 sceneState: Element.SceneState, 39 transition: TransitionState.Transition, 40 value: IntSize, 41 ): IntSize { 42 fun anchorSizeIn(scene: SceneKey): IntSize { 43 val size = 44 layoutImpl.elements[anchor]?.sceneStates?.get(scene)?.targetSize?.takeIf { 45 it != Element.SizeUnspecified 46 } 47 ?: throwMissingAnchorException( 48 transformation = "AnchoredSize", 49 anchor = anchor, 50 scene = scene, 51 ) 52 53 return IntSize( 54 width = if (anchorWidth) size.width else value.width, 55 height = if (anchorHeight) size.height else value.height, 56 ) 57 } 58 59 // This simple implementation assumes that the size of [element] is the same as the size of 60 // the [anchor] in [scene], so simply transform to the size of the anchor in the other 61 // scene. 62 return if (scene == transition.fromScene) { 63 anchorSizeIn(transition.toScene) 64 } else { 65 anchorSizeIn(transition.fromScene) 66 } 67 } 68 } 69