• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.demo
18 
19 import androidx.compose.animation.core.tween
20 import androidx.compose.foundation.background
21 import androidx.compose.foundation.border
22 import androidx.compose.foundation.clickable
23 import androidx.compose.foundation.layout.Box
24 import androidx.compose.foundation.layout.Column
25 import androidx.compose.foundation.layout.fillMaxSize
26 import androidx.compose.foundation.layout.padding
27 import androidx.compose.foundation.layout.size
28 import androidx.compose.foundation.shape.CircleShape
29 import androidx.compose.runtime.Composable
30 import androidx.compose.runtime.rememberCoroutineScope
31 import androidx.compose.ui.Alignment
32 import androidx.compose.ui.Modifier
33 import androidx.compose.ui.graphics.Color
34 import androidx.compose.ui.unit.dp
35 import com.android.compose.animation.scene.ContentScope
36 import com.android.compose.animation.scene.ElementKey
37 import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
38 import com.android.compose.animation.scene.SceneKey
39 import com.android.compose.animation.scene.SceneTransitionLayout
40 import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState
41 import com.android.compose.animation.scene.transitions
42 
43 object ParentSTL {
44     object Scenes {
45         val Left = SceneKey("Left")
46         val Right = SceneKey("Right")
47     }
48 }
49 
50 object ChildSTL {
51     object Scenes {
52         val Top = SceneKey("Top")
53         val Bottom = SceneKey("Bottom")
54     }
55 }
56 
57 object Elements {
58     val Shared = ElementKey("Shared")
59     val NotShared = ElementKey("NotShared")
60 }
61 
62 @Composable
NestedSharedElementDemonull63 fun NestedSharedElementDemo(modifier: Modifier = Modifier) {
64     Column(modifier) {
65         val state =
66             rememberMutableSceneTransitionLayoutState(
67                 ParentSTL.Scenes.Left,
68                 transitions {
69                     from(ParentSTL.Scenes.Left, to = ParentSTL.Scenes.Right) {
70                         spec = tween(1500)
71                         translate(Elements.NotShared, y = (-100).dp)
72                         fade(Elements.NotShared)
73                         scaleSize(Elements.NotShared, 0.5f, 0.5f)
74                     }
75                 },
76             )
77         val childState =
78             rememberMutableSceneTransitionLayoutState(
79                 ChildSTL.Scenes.Top,
80                 transitions {
81                     from(ChildSTL.Scenes.Top, to = ChildSTL.Scenes.Bottom) {
82                         spec = tween(1500)
83                         translate(Elements.NotShared, x = 100.dp)
84                         fade(Elements.NotShared)
85                         scaleSize(Elements.NotShared, 0.5f, 0.5f)
86                     }
87                 },
88             )
89         val scope = rememberCoroutineScope()
90         SceneTransitionLayout(
91             state,
92             Modifier.padding(16.dp)
93                 .border(3.dp, Color.Blue)
94                 .clickable {
95                     val targetScene =
96                         when (state.currentScene) {
97                             ParentSTL.Scenes.Left -> ParentSTL.Scenes.Right
98                             else -> ParentSTL.Scenes.Left
99                         }
100                     state.setTargetScene(targetScene, scope)
101                 }
102                 .padding(16.dp),
103         ) {
104             scene(ParentSTL.Scenes.Left) {
105                 Box(Modifier.fillMaxSize()) {
106                     ChildSTL(
107                         childState,
108                         Modifier.align(Alignment.Center).fillMaxSize(fraction = 0.5f),
109                     )
110                 }
111             }
112             scene(ParentSTL.Scenes.Right) {
113                 Box(Modifier.fillMaxSize()) {
114                     SharedElement(Modifier.size(30.dp).align(Alignment.TopEnd))
115                 }
116             }
117         }
118     }
119 }
120 
121 @Composable
ContentScopenull122 private fun ContentScope.ChildSTL(
123     state: MutableSceneTransitionLayoutState,
124     modifier: Modifier = Modifier,
125 ) {
126     val scope = rememberCoroutineScope()
127     NestedSceneTransitionLayout(
128         state,
129         modifier.border(3.dp, Color.Red).clickable {
130             val targetScene =
131                 when (state.currentScene) {
132                     ChildSTL.Scenes.Top -> ChildSTL.Scenes.Bottom
133                     else -> ChildSTL.Scenes.Top
134                 }
135             state.setTargetScene(targetScene, scope)
136         },
137     ) {
138         scene(ChildSTL.Scenes.Top) {
139             Box(Modifier.fillMaxSize()) {
140                 Box(
141                     Modifier.align(Alignment.TopEnd)
142                         .element(Elements.NotShared)
143                         .size(80.dp)
144                         .background(Color.Blue)
145                 )
146                 SharedElement(Modifier.size(100.dp))
147             }
148         }
149         scene(ChildSTL.Scenes.Bottom) {
150             Box(Modifier.fillMaxSize()) {
151                 SharedElement(Modifier.align(Alignment.BottomStart).size(60.dp))
152             }
153         }
154     }
155 }
156 
157 @Composable
ContentScopenull158 private fun ContentScope.SharedElement(modifier: Modifier = Modifier) {
159     Box(modifier.element(Elements.Shared).background(Color.Green, CircleShape))
160 }
161