CopyPastor

Detecting plagiarism made easy.

Score: 0.816989004611969; Reported for: String similarity Open both answers

Possible Plagiarism

Reposted on 2024-11-20
by Thracian

Original Post

Original - Posted on 2024-11-19
by Thracian



            
Present in both answers; Present only in the new answer; Present only in the old answer;

As suggested in Jan Itor's answer setting delay time a bit longer than exit animation lets enter animations run with specified easing. Otherwise enter animations still run but faster as in gif below.
[![enter image description here][1]][1]

With this snippet
@Composable private fun StaggeredList( filter: String, itemList: List<SomeData>, ) { BoxWithConstraints( modifier = Modifier ) { val itemWidth = (maxWidth - 8.dp) / 2 val heightList by remember { mutableStateOf( List(10) { index -> if (index == 0) { 200.dp } else Random.nextInt(120, 200).dp } ) } FlowRow( modifier = Modifier, maxItemsInEachRow = 2, horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { itemList.forEachIndexed { index, it -> key(it.id) { var visible by remember { mutableStateOf(false) } LaunchedEffect(filter) { visible = false delay(1500) visible = true } AnimatedVisibility( visible = visible, enter = fadeIn(tween(1500)) + slideInVertically(tween(1500)) { it / 2 }, exit = fadeOut(tween(1500)) + slideOutVertically(tween(1500)) { it / 2 } ) { MyRow( modifier = Modifier.size(itemWidth, heightList[index]), item = it ) } } } } } }

But setting a delay longer in composable causes scrollable LazyColumn to be resized and items to be displayed below. To solve this i retrieved FlowRow height before and set it as height. Also i decided using keys that not only unique to data but also to filtering as well with `key(it.id + filter)`
@Composable private fun StaggeredList( filter: String, itemList: List<SomeData>, ) { BoxWithConstraints( modifier = Modifier ) {
val itemWidth = (maxWidth - 8.dp) / 2
val heightList by remember { mutableStateOf( List(10) { index -> if (index == 0) { 200.dp } else Random.nextInt(120, 200).dp } ) }
var height by remember { mutableStateOf(0.dp) }
val density = LocalDensity.current
FlowRow( modifier = Modifier .onGloballyPositioned { val newHeight = it.size.height if (newHeight != 0) { height = with(density) { newHeight.toDp() } } } .heightIn(min = height) .border(2.dp, Color.Green), maxItemsInEachRow = 2, horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { itemList.forEachIndexed { index, it ->
// 🔥 These keys are unique for items for every filtering // without filter if items exist from previous filtering // they don't leave recomposition key(it.id + filter) {
var visible by remember { mutableStateOf(false) }
LaunchedEffect(filter) { visible = false delay(250) visible = true height = 0.dp }
AnimatedVisibility( visible = visible, enter = fadeIn(tween(250)) + slideInVertically(tween(250)) { it / 2 }, exit = fadeOut(tween(250)) + slideOutVertically(tween(250)) { it / 2 } ) { MyRow( modifier = Modifier.size(itemWidth, heightList[index]), item = it ) } } } } } }
In this case by removing items from composition with filter unique keys i also forfeited all of the exit animations instead of in other case only items that are recomposed having exit animations while items that don't exist in new filter were removed.

[![enter image description here][2]][2]

[1]: https://i.sstatic.net/JpXPtJB2.gif [2]: https://i.sstatic.net/xVtarUXi.gif
I solved this in 2 ways but first way is not i preferred for my implementation because it removes every item from composition and in a scrollable list/LazyColumn desired animation runs below visible area.
class SomeViewModel : ViewModel() { private val list = listOf( SomeData(id = "1", value = "Row1"), SomeData(id = "2", value = "Row2"), SomeData(id = "3", value = "Row3"), SomeData(id = "4", value = "Row4"), SomeData(id = "5", value = "Row5") ) var itemList by mutableStateOf(list) var filter: Int = 0 fun filter() { if (filter % 3 == 0) { itemList = listOf( list[0], list[1], list[2] ) } else if (filter % 3 == 1) { itemList = listOf( list[1], list[2] ) } else { itemList = listOf( list[0], list[2], list[3] ) } filter++ } } data class SomeData(val id: String, val value: String)
pass this `filter` in ViewModel to Composable that contains `FlowRow`

@Composable fun MyComposable(someViewModel: SomeViewModel) { Column(modifier = Modifier.fillMaxSize().background(backgroundColor)) { val itemList = someViewModel.itemList LazyColumn( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(8.dp), contentPadding = PaddingValues(16.dp) ) { items(5) { Box( modifier = Modifier .background(Color.Red, RoundedCornerShape(16.dp)) .fillMaxWidth().height(100.dp) ) } item { Button( modifier = Modifier.padding(16.dp).fillMaxWidth(), onClick = { someViewModel.filter() } ) { Text("Filter") } } item { StaggeredList( filter = someViewModel.filter.toString(), itemList = itemList ) } } } }
And in this composable `key(it.id + filter)` to remove every item from composition when filter changes but this approach makes items below visible area since every item is removed and added to recomposition in a LazyColumn.
@OptIn(ExperimentalLayoutApi::class) @Composable private fun StaggeredList( filter: String, itemList: List<SomeData>, ) { BoxWithConstraints( modifier = Modifier ) { val itemWidth = (maxWidth - 8.dp) / 2 FlowRow( modifier = Modifier.fillMaxSize(), maxItemsInEachRow = 2, horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { itemList.forEachIndexed { index, it -> key(it.id + filter) { var visible by remember { mutableStateOf(false) } LaunchedEffect(Unit) { visible = false println("Composing ${it.id},") delay(250) visible = true } AnimatedVisibility( visible = visible, enter = fadeIn(tween(250)) + slideInVertically(tween(250)) { it / 2 }, exit = fadeOut(tween(250)) + slideOutVertically(tween(250)) { it / 2 } ) { MyRow( modifier = Modifier.size(itemWidth, 200.dp), item = it ) } } } } } }

In second approach i used same key, but using `filter` as `LaunchedEffect` key to restart animation but this time fadeIn() and fadeOut animations stopped working.
key(it.id) { var visible by remember { mutableStateOf(false) } LaunchedEffect(filter) { visible = false println("Composing ${it.id},") delay(250) visible = true } }
And Row composable is
@Composable fun MyRow( modifier: Modifier = Modifier, item: SomeData, ) { var counter by remember { mutableIntStateOf(0) } Column( modifier = modifier .shadow(2.dp, RoundedCornerShape(16.dp)) .background(Color.White, RoundedCornerShape(16.dp)) .padding(16.dp) ) { Text( "id: ${item.id}, value: ${item.value}" ) Spacer(modifier = Modifier.weight(1f)) Button( modifier = Modifier.fillMaxWidth(), onClick = { counter++ } ) { Text("Counter: $counter") } } }

        
Present in both answers; Present only in the new answer; Present only in the old answer;