Experiement with Modifier.animateBounds(modifier: Modifier)
Add Modifier.animateBounds to demos. Will perfect it more
based on user feedback, and move to animation lib when
LookaheadLayout is stable.
Test: Ran demos
Change-Id: Ia79c5f53179af7949c04730a5a19d5d5b3a5874d
diff --git a/compose/animation/animation/integration-tests/animation-demos/build.gradle b/compose/animation/animation/integration-tests/animation-demos/build.gradle
index a44d97e..5a12844 100644
--- a/compose/animation/animation/integration-tests/animation-demos/build.gradle
+++ b/compose/animation/animation/integration-tests/animation-demos/build.gradle
@@ -1,3 +1,5 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
plugins {
id("AndroidXPlugin")
id("com.android.library")
@@ -23,6 +25,10 @@
debugImplementation(project(":compose:ui:ui-tooling"))
}
+tasks.withType(KotlinCompile).configureEach {
+ kotlinOptions.freeCompilerArgs += "-Xcontext-receivers"
+}
+
android {
namespace "androidx.compose.animation.demos"
}
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
index ad98bd2..9243b74d 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
@@ -35,9 +35,10 @@
import androidx.compose.animation.demos.layoutanimation.ScaleEnterExitDemo
import androidx.compose.animation.demos.layoutanimation.ScreenTransitionDemo
import androidx.compose.animation.demos.layoutanimation.ShrineCartDemo
+import androidx.compose.animation.demos.lookahead.AnimateBoundsModifierDemo
import androidx.compose.animation.demos.lookahead.CraneDemo
import androidx.compose.animation.demos.lookahead.LookaheadLayoutWithAlignmentLinesDemo
-import androidx.compose.animation.demos.lookahead.LookaheadMeasurePlaceDemo
+import androidx.compose.animation.demos.lookahead.LookaheadWithFlowRowDemo
import androidx.compose.animation.demos.lookahead.LookaheadWithMovableContentDemo
import androidx.compose.animation.demos.lookahead.ScreenSizeChangeDemo
import androidx.compose.animation.demos.singlevalue.SingleValueAnimationDemo
@@ -98,6 +99,9 @@
DemoCategory(
"\uD83E\uDD7C\uD83E\uDDD1\u200D\uD83D\uDD2C Lookahead Animation Demos",
listOf(
+ ComposableDemo("AnimateBoundsModifier") {
+ AnimateBoundsModifierDemo()
+ },
ComposableDemo("Crane Nested Shared Element") { CraneDemo() },
ComposableDemo("Screen Size Change Demo") { ScreenSizeChangeDemo() },
ComposableDemo("Lookahead With Movable Content") {
@@ -106,7 +110,7 @@
ComposableDemo("Lookahead With Alignment Lines") {
LookaheadLayoutWithAlignmentLinesDemo()
},
- ComposableDemo("Flow Row Lookahead") { LookaheadMeasurePlaceDemo() },
+ ComposableDemo("Flow Row Lookahead") { LookaheadWithFlowRowDemo() },
)
),
DemoCategory(
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
new file mode 100644
index 0000000..801a1ff
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2022 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.
+ */
+
+@file:OptIn(ExperimentalComposeUiApi::class)
+
+package androidx.compose.animation.demos.lookahead
+
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.AnimationVector
+import androidx.compose.animation.core.FiniteAnimationSpec
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.TwoWayConverter
+import androidx.compose.animation.core.VectorConverter
+import androidx.compose.animation.core.spring
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.layout.LookaheadLayoutScope
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.round
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+context(LookaheadLayoutScope)
+fun Modifier.animateBounds(
+ modifier: Modifier,
+ sizeAnimationSpec: FiniteAnimationSpec<IntSize> = spring(
+ Spring.DampingRatioNoBouncy,
+ Spring.StiffnessMediumLow
+ ),
+ positionAnimationSpec: FiniteAnimationSpec<IntOffset> = spring(
+ Spring.DampingRatioNoBouncy,
+ Spring.StiffnessMediumLow
+ ),
+) = composed {
+ val coroutineScope = rememberCoroutineScope()
+ var placementOffset: IntOffset by remember { mutableStateOf(IntOffset.Zero) }
+
+ val offsetAnimation = remember {
+ DeferredAnimation(coroutineScope, IntOffset.VectorConverter)
+ }
+ val sizeAnimation = remember {
+ DeferredAnimation(coroutineScope, IntSize.VectorConverter)
+ }
+ val outerSizeAnimation = remember {
+ DeferredAnimation(coroutineScope, IntSize.VectorConverter)
+ }
+ // The measure logic in `intermediateLayout` is skipped in the lookahead pass, as
+ // intermediateLayout is expected to produce intermediate stages of a layout transform.
+ // When the measure block is invoked after lookahead pass, the lookahead size of the
+ // child will be accessible as a parameter to the measure block.
+ this
+ .intermediateLayout { measurable, constraints, lookaheadSize ->
+ outerSizeAnimation.updateTarget(lookaheadSize, sizeAnimationSpec)
+ val (w, h) = outerSizeAnimation.value ?: lookaheadSize
+ measurable
+ .measure(constraints)
+ .run {
+ layout(w, h) {
+ place(0, 0)
+ }
+ }
+ }
+ .then(modifier)
+ .onPlaced { lookaheadScopeCoordinates, layoutCoordinates ->
+ // This block of code has the LookaheadCoordinates of the LookaheadLayout
+ // as the first parameter, and the coordinates of this modifier as the second
+ // parameter.
+
+ // localLookaheadPositionOf returns the *target* position of this
+ // modifier in the LookaheadLayout's local coordinates.
+ val targetOffset = lookaheadScopeCoordinates
+ .localLookaheadPositionOf(
+ layoutCoordinates
+ )
+ .round()
+ offsetAnimation.updateTarget(targetOffset, positionAnimationSpec)
+
+ // localPositionOf returns the *current* position of this
+ // modifier in the LookaheadLayout's local coordinates.
+ placementOffset = lookaheadScopeCoordinates
+ .localPositionOf(
+ layoutCoordinates, Offset.Zero
+ )
+ .round()
+ }
+ .intermediateLayout { measurable, _, lookaheadSize ->
+ // When layout changes, the lookahead pass will calculate a new final size for the
+ // child modifier. This lookahead size can be used to animate the size
+ // change, such that the animation starts from the current size and gradually
+ // change towards `lookaheadSize`.
+ sizeAnimation.updateTarget(lookaheadSize, sizeAnimationSpec)
+ // Reads the animation size if the animation is set up. Otherwise (i.e. first
+ // frame), use the lookahead size without animation.
+ val (width, height) = sizeAnimation.value ?: lookaheadSize
+ // Creates a fixed set of constraints using the animated size
+ val animatedConstraints = Constraints.fixed(width, height)
+ // Measure child/children with animated constraints.
+ val placeable = measurable.measure(animatedConstraints)
+ layout(placeable.width, placeable.height) {
+ // offsetAnimation will animate the target position whenever it changes.
+ // In order to place the child at the animated position, we need to offset
+ // the child based on the target and current position in LookaheadLayout.
+ val (x, y) = offsetAnimation.value?.let { it - placementOffset }
+ // If offsetAnimation has not been set up yet (i.e. in the first frame),
+ // skip the animation
+ ?: (offsetAnimation.target!! - placementOffset)
+ placeable.place(x, y)
+ }
+ }
+}
+
+// Experimenting with a way to initialize animation during measurement && only take the last target
+// change in a frame (if the target was changed multiple times in the same frame) as the
+// animation target.
+internal class DeferredAnimation<T, V : AnimationVector>(
+ coroutineScope: CoroutineScope,
+ vectorConverter: TwoWayConverter<T, V>
+) {
+ val value: T?
+ get() = animatable?.value ?: target
+ var target: T? by mutableStateOf(null)
+ private set
+ private var animationSpec: FiniteAnimationSpec<T> = spring()
+ private var animatable: Animatable<T, V>? = null
+
+ init {
+ coroutineScope.launch {
+ snapshotFlow { target }.collect { target ->
+ if (target != null && target != animatable?.targetValue) {
+ animatable?.run {
+ launch { animateTo(target, animationSpec) }
+ } ?: Animatable(target, vectorConverter).let {
+ animatable = it
+ }
+ }
+ }
+ }
+ }
+
+ fun updateTarget(targetValue: T, animationSpec: FiniteAnimationSpec<T>) {
+ target = targetValue
+ this.animationSpec = animationSpec
+ }
+}
\ No newline at end of file
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifierDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifierDemo.kt
new file mode 100644
index 0000000..2f89ffb
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifierDemo.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2022 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 androidx.compose.animation.demos.lookahead
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.LookaheadLayout
+import androidx.compose.ui.layout.MeasurePolicy
+import androidx.compose.ui.unit.dp
+import java.lang.Integer.max
+import kotlin.random.Random
+
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+fun AnimateBoundsModifierDemo() {
+ var height by remember {
+ mutableStateOf(200)
+ }
+ var left by remember {
+ mutableStateOf(0)
+ }
+ var top by remember {
+ mutableStateOf(0)
+ }
+ var right by remember {
+ mutableStateOf(0)
+ }
+ var bottom by remember {
+ mutableStateOf(0)
+ }
+ var weight by remember {
+ mutableStateOf(2f)
+ }
+
+ LookaheadLayout(
+ modifier = Modifier
+ .fillMaxSize()
+ .clickable {
+ height = Random.nextInt(10, 300)
+ weight = Random
+ .nextDouble(0.5, 4.5)
+ .toFloat()
+
+ left = Random.nextInt(0, 200)
+ top = Random.nextInt(0, 100)
+ right = Random.nextInt(0, 200)
+ bottom = Random.nextInt(0, 100)
+ },
+ content = {
+ Column {
+ Box(
+ Modifier
+ .fillMaxHeight(0.5f)
+ .fillMaxSize()
+ ) {
+ Box(
+ Modifier
+ .background(Color.Gray)
+ .animateBounds(
+ Modifier.padding(left.dp, top.dp, right.dp, bottom.dp)
+ )
+ .background(Color.Red)
+ .fillMaxSize()
+ )
+ }
+ Row(Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically) {
+ Box(
+ Modifier
+ .animateBounds(
+ Modifier
+ .weight(weight)
+ .height(height.dp)
+ )
+ .background(Color(0xffa2d2ff), RoundedCornerShape(5.dp))
+ )
+ Box(
+ Modifier
+ .animateBounds(
+ Modifier
+ .weight(1f)
+ .height(height.dp)
+ )
+ .background(Color(0xfffff3b0))
+ )
+ }
+ }
+ }, measurePolicy = lookaheadMeasurePolicy
+ )
+}
+
+internal val lookaheadMeasurePolicy = MeasurePolicy { measurables, constraints ->
+ val contentConstraints = constraints.copy(minWidth = 0, minHeight = 0)
+ val placeables = measurables.map { it.measure(contentConstraints) }
+ val maxWidth: Int = max(placeables.maxOf { it.width }, constraints.minWidth)
+ val maxHeight = max(placeables.maxOf { it.height }, constraints.minHeight)
+ // Position the children.
+ layout(maxWidth, maxHeight) {
+ placeables.forEach {
+ it.place(0, 0)
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadMeasurePlaceDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt
similarity index 72%
rename from compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadMeasurePlaceDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt
index ae4917b..8a767c5 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadMeasurePlaceDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt
@@ -36,85 +36,108 @@
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.LookaheadLayout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import kotlin.math.max
+@OptIn(ExperimentalComposeUiApi::class)
@Composable
-fun LookaheadMeasurePlaceDemo() {
+fun LookaheadWithFlowRowDemo() {
Column(
+ modifier = Modifier.padding(10.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
var isHorizontal by remember { mutableStateOf(true) }
- Button(modifier = Modifier.padding(top = 20.dp, bottom = 20.dp),
- onClick = { isHorizontal = !isHorizontal }) {
- Text("Toggle")
- }
- Column(Modifier.background(Color(0xfffdedac), RoundedCornerShape(10)).padding(10.dp)) {
- Text("Scene Host")
- SceneHost(
- Modifier.height(200.dp).fillMaxWidth().wrapContentSize(Alignment.CenterStart)
- ) {
- MyFlowRow {
- Box(
- Modifier.height(50.dp)
- .fillMaxWidth(if (isHorizontal) 0.4f else 1f)
- .sharedElement()
- .background(colors[0], RoundedCornerShape(10))
- )
- Box(
- Modifier.height(50.dp)
- .fillMaxWidth(if (isHorizontal) 0.2f else 0.4f)
- .sharedElement()
- .background(colors[1], RoundedCornerShape(10))
- )
- Box(
- Modifier.height(50.dp)
- .fillMaxWidth(if (isHorizontal) 0.2f else 0.4f)
- .sharedElement()
- .background(colors[2], RoundedCornerShape(10))
- )
- }
- Box(Modifier.size(if (isHorizontal) 200.dp else 100.dp))
- }
+ Column(
+ Modifier
+ .background(Color(0xfffdedac), RoundedCornerShape(10))
+ .padding(10.dp)
+ ) {
+ Text("LookaheadLayout + Modifier.animateBounds")
+ LookaheadLayout(
+ measurePolicy = lookaheadMeasurePolicy,
+ content = {
+ MyFlowRow(
+ modifier = Modifier
+ .height(200.dp)
+ .fillMaxWidth()
+ .wrapContentSize(Alignment.CenterStart)
+ ) {
+ Box(
+ Modifier
+ .height(50.dp)
+ .animateBounds(
+ Modifier.fillMaxWidth(if (isHorizontal) 0.4f else 1f)
+ )
+ .background(colors[0], RoundedCornerShape(10))
+ )
+ Box(
+ Modifier
+ .height(50.dp)
+ .animateBounds(
+ Modifier.fillMaxWidth(if (isHorizontal) 0.2f else 0.4f)
+ )
+ .background(colors[1], RoundedCornerShape(10))
+ )
+ Box(
+ Modifier
+ .height(50.dp)
+ .animateBounds(
+ Modifier.fillMaxWidth(if (isHorizontal) 0.2f else 0.4f)
+ )
+ .background(colors[2], RoundedCornerShape(10))
+ )
+ }
+ Box(Modifier.size(if (isHorizontal) 200.dp else 100.dp))
+ })
}
Spacer(Modifier.size(50.dp))
- Column(Modifier.background(Color(0xfffdedac), RoundedCornerShape(10)).padding(10.dp)) {
+ Column(
+ Modifier
+ .background(Color(0xfffdedac), RoundedCornerShape(10))
+ .padding(10.dp)
+ ) {
Text("Animating Width")
MyFlowRow(
- modifier = Modifier.height(200.dp).fillMaxWidth()
+ modifier = Modifier
+ .height(200.dp)
+ .fillMaxWidth()
.wrapContentSize(Alignment.CenterStart)
) {
Box(
- Modifier.height(50.dp)
+ Modifier
+ .height(50.dp)
.fillMaxWidth(animateFloatAsState(if (isHorizontal) 0.4f else 1f).value)
.background(colors[0], RoundedCornerShape(10))
)
Box(
- Modifier.height(50.dp)
+ Modifier
+ .height(50.dp)
.fillMaxWidth(animateFloatAsState(if (isHorizontal) 0.2f else 0.4f).value)
.background(colors[1], RoundedCornerShape(10))
)
Box(
- Modifier.height(50.dp)
+ Modifier
+ .height(50.dp)
.fillMaxWidth(animateFloatAsState(if (isHorizontal) 0.2f else 0.4f).value)
.background(colors[2], RoundedCornerShape(10))
)
}
}
- }
-}
-fun printStack(tag: String) {
- Thread.currentThread().stackTrace.forEach {
- println("$tag, $it")
+ Button(modifier = Modifier.padding(top = 20.dp, bottom = 20.dp),
+ onClick = { isHorizontal = !isHorizontal }) {
+ Text("Toggle")
+ }
}
}
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/ScreenSizeChangeDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/ScreenSizeChangeDemo.kt
index 2009f4c..a62bf4d 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/ScreenSizeChangeDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/ScreenSizeChangeDemo.kt
@@ -33,6 +33,8 @@
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Icon
@@ -56,6 +58,7 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
@@ -68,13 +71,16 @@
// A surface container using the 'background' color from the theme
var state by remember { mutableStateOf(DisplayState.Tablet) }
Box(
- modifier = Modifier.fillMaxSize().background(Color.Black).clickable(
- interactionSource = remember { MutableInteractionSource() },
- indication = null
- ) {
- state =
- if (state == DisplayState.Tablet) DisplayState.Compact else DisplayState.Tablet
- },
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color.Black)
+ .clickable(
+ interactionSource = remember { MutableInteractionSource() },
+ indication = null
+ ) {
+ state =
+ if (state == DisplayState.Tablet) DisplayState.Compact else DisplayState.Tablet
+ },
contentAlignment = Alignment.TopStart
) {
Root(state)
@@ -115,14 +121,18 @@
Spacer(Modifier.weight(1f))
Icon(
Icons.Default.Delete,
- modifier = Modifier.padding(2.dp)
- .background(Color.White, RoundedCornerShape(3.dp)).padding(6.dp),
+ modifier = Modifier
+ .padding(2.dp)
+ .background(Color.White, RoundedCornerShape(3.dp))
+ .padding(6.dp),
contentDescription = null
)
Icon(
Icons.Default.Menu,
- modifier = Modifier.padding(2.dp)
- .background(Color.White, RoundedCornerShape(3.dp)).padding(6.dp),
+ modifier = Modifier
+ .padding(2.dp)
+ .background(Color.White, RoundedCornerShape(3.dp))
+ .padding(6.dp),
contentDescription = null
)
}
@@ -136,11 +146,17 @@
fun Root(state: DisplayState) {
SceneHost {
Row(
- if (state == DisplayState.Compact) {
- Modifier.requiredWidth(800.dp).fillMaxHeight()
- } else {
- Modifier.fillMaxSize()
- }.sharedElement()
+ Modifier
+ .animateBounds(
+ if (state == DisplayState.Compact) {
+ Modifier
+ .wrapContentSize(align = Alignment.TopStart, unbounded = true)
+ .requiredWidth(800.dp)
+ .fillMaxHeight()
+ } else {
+ Modifier.fillMaxSize()
+ }
+ )
.background(Color(0xffeae7f2))
.padding(top = 10.dp, start = 10.dp, end = 10.dp)
) {
@@ -283,7 +299,9 @@
cardData.content,
fontSize = 13.sp,
color = Color.Gray,
- modifier = Modifier.padding(start = 10.dp).animateSizeAndSkipToFinalLayout()
+ modifier = Modifier
+ .padding(start = 10.dp)
+ .animateSizeAndSkipToFinalLayout()
)
}
}
@@ -309,7 +327,9 @@
messageData.content,
fontSize = 13.sp,
color = Color.Gray,
- modifier = Modifier.padding(start = 10.dp).animateSizeAndSkipToFinalLayout()
+ modifier = Modifier
+ .padding(start = 10.dp)
+ .animateSizeAndSkipToFinalLayout()
)
Spacer(Modifier.size(10.dp))
Row(modifier = Modifier.fillMaxWidth()) {
@@ -341,16 +361,18 @@
fun SceneScope.NavRail(state: DisplayState) {
Column(
Modifier
- .then(
- if (state == DisplayState.Tablet) Modifier.width(200.dp) else Modifier.width(
- IntrinsicSize.Min
- )
+ .animateBounds(
+ if (state == DisplayState.Tablet)
+ Modifier.width(200.dp)
+ else
+ Modifier.width(IntrinsicSize.Min)
)
.padding(top = 20.dp, end = 5.dp)
) {
Row(
Modifier
- .fillMaxWidth().animateSizeAndSkipToFinalLayout()
+ .fillMaxWidth()
+ .animateSizeAndSkipToFinalLayout()
.padding(5.dp), horizontalArrangement = Arrangement.SpaceBetween
) {
if (state == DisplayState.Tablet) {
@@ -360,7 +382,9 @@
imageVector = Icons.Outlined.Menu,
contentDescription = null,
tint = Color.Gray,
- modifier = Modifier.width(40.dp).sharedElement()
+ modifier = Modifier
+ .width(40.dp)
+ .sharedElement()
)
}
Spacer(modifier = Modifier.size(10.dp))
@@ -381,7 +405,10 @@
if (state == DisplayState.Tablet) {
Text(
"Compose",
- Modifier.padding(start = 30.dp),
+ Modifier
+ .padding(start = 30.dp)
+ .clipToBounds()
+ .wrapContentWidth(align = Alignment.CenterHorizontally, unbounded = true),
color = Color.Gray,
fontWeight = FontWeight.Bold
)
@@ -414,6 +441,8 @@
text,
Modifier
.weight(1f)
+ .clipToBounds()
+ .wrapContentWidth(align = Alignment.Start, unbounded = true)
.padding(start = 15.dp),
color = Color.Gray,
fontWeight = FontWeight.Bold,