1 /* <lambda>null2 * 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 @file:OptIn(ExperimentalMotionApi::class) 18 19 package androidx.constraintlayout.compose.demos 20 21 import androidx.compose.animation.core.animateFloatAsState 22 import androidx.compose.animation.core.tween 23 import androidx.compose.foundation.background 24 import androidx.compose.foundation.layout.Arrangement 25 import androidx.compose.foundation.layout.Box 26 import androidx.compose.foundation.layout.Column 27 import androidx.compose.foundation.layout.Row 28 import androidx.compose.foundation.layout.fillMaxSize 29 import androidx.compose.foundation.layout.fillMaxWidth 30 import androidx.compose.foundation.layout.size 31 import androidx.compose.material.Button 32 import androidx.compose.material.Text 33 import androidx.compose.runtime.Composable 34 import androidx.compose.runtime.derivedStateOf 35 import androidx.compose.runtime.getValue 36 import androidx.compose.runtime.mutableStateOf 37 import androidx.compose.runtime.remember 38 import androidx.compose.runtime.setValue 39 import androidx.compose.ui.Modifier 40 import androidx.compose.ui.graphics.Color 41 import androidx.compose.ui.layout.layoutId 42 import androidx.compose.ui.tooling.preview.Preview 43 import androidx.compose.ui.unit.dp 44 import androidx.constraintlayout.compose.ChainStyle 45 import androidx.constraintlayout.compose.ExperimentalMotionApi 46 import androidx.constraintlayout.compose.MotionLayout 47 import androidx.constraintlayout.compose.MotionScene 48 49 private const val STAGGERED_VALUE = 0.4f 50 51 @Preview 52 @Composable 53 fun SimpleStaggeredDemo() { 54 var mode by remember { mutableStateOf(StaggeredMode.Normal) } 55 var animateToEnd by remember { mutableStateOf(false) } 56 val progress by 57 animateFloatAsState( 58 targetValue = if (animateToEnd) 1f else 0f, 59 animationSpec = tween(3000), 60 ) 61 val boxesId: IntArray = remember { IntArray(10) { it } } 62 val staggeredValue by remember { 63 derivedStateOf { 64 when (mode) { 65 StaggeredMode.Inverted -> -STAGGERED_VALUE 66 else -> STAGGERED_VALUE 67 } 68 } 69 } 70 71 Column(Modifier.fillMaxSize()) { 72 MotionLayout( 73 remember(mode) { 74 MotionScene { 75 val refs = boxesId.map { createRefFor(it) }.toTypedArray() 76 val weights = 77 when (mode) { 78 StaggeredMode.Custom -> boxesId.map { it.toFloat() }.shuffled() 79 else -> boxesId.map { Float.NaN } 80 } 81 82 defaultTransition( 83 constraintSet { 84 createHorizontalChain(*refs, chainStyle = ChainStyle.Packed(0f)) 85 refs.forEachIndexed { index, ref -> 86 constrain(ref) { staggeredWeight = weights[index] } 87 } 88 }, 89 constraintSet { 90 createVerticalChain(*refs, chainStyle = ChainStyle.Packed(1f)) 91 constrain(*refs) { end.linkTo(parent.end) } 92 } 93 ) { 94 maxStaggerDelay = staggeredValue 95 } 96 } 97 }, 98 progress = progress, 99 Modifier.fillMaxWidth().weight(1f, true) 100 ) { 101 for (id in boxesId) { 102 Box(modifier = Modifier.size(25.dp).background(Color.Red).layoutId(id)) 103 } 104 } 105 Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { 106 Button(onClick = { animateToEnd = !animateToEnd }) { Text(text = "Run") } 107 Button( 108 onClick = { 109 mode = 110 when (mode) { 111 StaggeredMode.Normal -> StaggeredMode.Inverted 112 StaggeredMode.Inverted -> StaggeredMode.Custom 113 else -> StaggeredMode.Normal 114 } 115 } 116 ) { 117 Text(text = "Mode: ${mode.name}, Value: $staggeredValue") 118 } 119 } 120 } 121 } 122 123 private enum class StaggeredMode { 124 Normal, 125 Inverted, 126 Custom 127 } 128