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.geometry.Offset 20 import androidx.compose.ui.geometry.isSpecified 21 import com.android.compose.animation.scene.Element 22 import com.android.compose.animation.scene.ElementKey 23 import com.android.compose.animation.scene.ElementMatcher 24 import com.android.compose.animation.scene.Scene 25 import com.android.compose.animation.scene.SceneKey 26 import com.android.compose.animation.scene.SceneTransitionLayoutImpl 27 import com.android.compose.animation.scene.TransitionState 28 29 /** Anchor the translation of an element to another element. */ 30 internal class AnchoredTranslate( 31 override val matcher: ElementMatcher, 32 private val anchor: ElementKey, 33 ) : PropertyTransformation<Offset> { transformnull34 override fun transform( 35 layoutImpl: SceneTransitionLayoutImpl, 36 scene: Scene, 37 element: Element, 38 sceneValues: Element.SceneValues, 39 transition: TransitionState.Transition, 40 value: Offset, 41 ): Offset { 42 val anchor = layoutImpl.elements[anchor] ?: return value 43 fun anchorOffsetIn(scene: SceneKey): Offset? { 44 return anchor.sceneValues[scene]?.offset?.takeIf { it.isSpecified } 45 } 46 47 // [element] will move the same amount as [anchor] does. 48 // TODO(b/290184746): Also support anchors that are not shared but translated because of 49 // other transformations, like an edge translation. 50 val anchorFromOffset = anchorOffsetIn(transition.fromScene) ?: return value 51 val anchorToOffset = anchorOffsetIn(transition.toScene) ?: return value 52 val offset = anchorToOffset - anchorFromOffset 53 54 return if (scene.key == transition.toScene) { 55 Offset( 56 value.x - offset.x, 57 value.y - offset.y, 58 ) 59 } else { 60 Offset( 61 value.x + offset.x, 62 value.y + offset.y, 63 ) 64 } 65 } 66 } 67