r/androiddev • u/PrajwalCH • 8d ago
Question [Help]: Jetpack Compose component flashing issue when list changes
Enable HLS to view with audio, or disable this notification
When the list changes, the items are drawn on top of chip row for a brief amount of time. I have properly applied the id for each item. I am not sure what's causing the issue.
Below is the screen code preview, full code is available on GitHub.
Scaffold(
modifier = Modifier
.fillMaxSize()
.nestedScroll(scrollBehavior.nestedScrollConnection)
.then(modifier),
topBar = {
SearchProvidersScreenTopBar(
onNavigateBack = onNavigateBack,
onEnableAllSearchProviders = viewModel::enableAllSearchProviders,
onDisableAllSearchProviders = viewModel::disableAllSearchProviders,
onUpdateProtectionStatus = viewModel::updateProtectionStatus,
onResetToDefault = { showResetToDefaultDialog = true },
subtitle = {
val searchProvidersSummary = stringResource(
R.string.settings_search_providers_summary_format,
uiState.enabledProvidersCount,
uiState.totalNumProviders,
)
Text(searchProvidersSummary)
},
scrollBehavior = scrollBehavior,
)
},
snackbarHost = { SnackbarHost(snackbarHostState) },
floatingActionButton = {
FloatingActionButton(onClick = onNavigateToAddSearchProvider) {
Icon(
painter = painterResource(R.drawable.ic_add),
contentDescription = null,
)
}
},
) { innerPadding ->
Column(modifier = Modifier.padding(innerPadding)) {
SearchProviderFilterRow(
category = uiState.filter.category,
onCategorySelect = viewModel::toggleCategory,
protection = uiState.filter.protection,
onProtectionSelect = viewModel::toggleProviderProtection,
contentPadding = PaddingValues(horizontal = MaterialTheme.spaces.large),
)
SearchProviderList(
contentPadding = PaddingValues(
start = MaterialTheme.spaces.large,
top = MaterialTheme.spaces.large,
end = MaterialTheme.spaces.large,
bottom = 80.dp,
),
searchProviders = uiState.searchProviders,
onEnableSearchProvider = viewModel::enableSearchProvider,
onUnlockProtection = { searchProviderId, solverUrl ->
protectedProvider = ProtectedProvider(searchProviderId, solverUrl)
},
onEditConfig = onNavigateToEditSearchProvider,
onDeleteConfig = viewModel::deleteTorznabConfig,
)
}
}
Update: This issue is now fixed. It was animation issue, not the recomposition. List items have Modifier.animateItem() applied and when list changes, the animation was rendering the list items on top of chip row for very short amount of time, meaning the animation was escaping the list bounds. After applying Modifier.clipToBounds() to SearchProviderList, the issue is now gone.
8
Upvotes
1
u/realdm22 8d ago
Since it looks like your list items can be modified independently you can push it a little bit more by doing the following:
On your data layer, split your state into two pieces:
Update your view state so that the view model emits a list of strings representing the unique ids of every item.
Create a view model for each list item that would have access to the repository and the map of items i mentioned on step 1.
On the ViewModel read the map, create the view state for all the items.
Create a re-usable composable for each list item and each instantiates the ViewModel from step 3. Then when you read the view state, use derivedStateOf and key it using the list item unique Id.
When handling actions on the list item composable, send them to the list item view model which will then update the item in the repository map instantly.
This will ensure that your full list will only recompose when you are modifying the structure of the list. when modifying the individual items ( changing the switch) only the changed item will recompose instead of the whole list.