Anonymous
Ошибка перехода общего элемента Jetpack Compose?
Сообщение
Anonymous » 29 июн 2024, 19:18
Итак, у меня есть ошибка перехода общего элемента, или, может быть, я просто неправильно реализовал ее при компоновке, вы можете увидеть ошибку в этом видео.
как вы можете видеть сначала переход между экраном списка и экраном подробностей (добавить экран редактирования) работают правильно, и после открытия (добавить экран редактирования) из FAB, чтобы добавить новую заметку, переход сломан и просто показывает, что элемент исчез, и снова появляется без перехода в режим изменения размера, как в первый раз, эта проблема также возникает, если я очень быстро ищу заметки или удаляю и отменяю удаление заметки.
и это мой код
Код содержимого заметки:< /p>
Код: Выделить всё
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun NoteContent(
state: NoteState,
query: String,
onOrderChange: (NoteOrder) -> Unit,
onToggleOrderSectionClick: () -> Unit,
onDeleteClick: (Note) -> Unit,
onUndoClick: () -> Unit,
navigateToAddEdit: (Int, Int) -> Unit,
onQueryChange: (String) -> Unit,
sharedTransitionScope: SharedTransitionScope,
animatedVisibilityScope: AnimatedVisibilityScope
) {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
val staggeredGridState = rememberLazyStaggeredGridState()
with(sharedTransitionScope){
Scaffold(
floatingActionButton = {
FloatingActionButton(
onClick = {navigateToAddEdit(-1,-1)},
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(imageVector = Icons.Default.Add, contentDescription = "Add Note")
}
},
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
) { padding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 8.dp)
) {
LazyVerticalStaggeredGrid(
state = staggeredGridState,
columns = StaggeredGridCells.Fixed(2),
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(bottom = 4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalItemSpacing = 4.dp
) {
item(span = StaggeredGridItemSpan.FullLine) {
SearchBar(
query = query,
onQueryChange = onQueryChange,
onToggleOrderSectionClick = onToggleOrderSectionClick
)
}
item(span = StaggeredGridItemSpan.FullLine) {
AnimatedVisibility(
visible = state.isOrderSectionVisible,
enter = fadeIn() + slideInVertically(),
exit = fadeOut() + slideOutVertically()
) {
OrderRadio(modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp, horizontal = 8.dp),
noteOrder = state.noteOrder,
onOrderChange = { order ->
onOrderChange(order)
})
}
}
items(state.notes, key = { it.id ?: 0 }) { note ->
AnimatedVisibility(
visible = state.notes.isNotEmpty(),
enter = fadeIn(),
exit = fadeOut(),
) {
NoteItem(note = note,
modifier = Modifier
.padding(4.dp)
.fillMaxWidth()
.animateItem(
placementSpec = tween(
durationMillis = 300, delayMillis = 0
)
)
.sharedBounds(
rememberSharedContentState(key = "note/${note.id}"),
animatedVisibilityScope = animatedVisibilityScope,
enter = fadeIn(),
exit = fadeOut(),
resizeMode = SharedTransitionScope.ResizeMode.ScaleToBounds()
), // This line adds the placement animation
onDeleteClick = {
onDeleteClick(note)
scope.launch {
val result = snackbarHostState.showSnackbar(
message = "Note deleted", actionLabel = "Undo"
)
if (result == SnackbarResult.ActionPerformed) {
onUndoClick()
}
}
},
onClick = {
note.id?.let { it1 -> navigateToAddEdit(it1, note.color) }
})
}
}
}
AnimatedVisibility(
visible = state.notes.isEmpty(),
enter = fadeIn(),
exit = fadeOut(),
) {
EmptyNote(
isSearchActive = state.isSearchActive,
)
}
}
}
}
}
Код AddEditScreen:
Код: Выделить всё
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun AddEditNoteScreen(
navController: NavController,
noteColor : Int,
noteId:Int?,
viewModel: AddEditViewModel = hiltViewModel(),
sharedTransitionScope: SharedTransitionScope,
animatedVisibilityScope: AnimatedVisibilityScope
){
val titleState = viewModel.title.value
val contentState = viewModel.content.value
val snackbarHostState = remember { SnackbarHostState() }
Log.d("test", noteColor.toString())
val backgroundAnimateableColor = remember {
Animatable(
Color(if (noteColor != -1) noteColor else viewModel.color.value)
)
}
if(noteColor != -1){
viewModel.onEvent(AddEditNoteEvent.ChangeColor(noteColor))
}
val scope = rememberCoroutineScope()
LaunchedEffect(key1 = true) {
viewModel.eventFlow.collectLatest { event ->
when (event) {
is AddEditViewModel.UiEvent.ShowSnackbar -> {
snackbarHostState.showSnackbar(
message = event.message
)
}
is AddEditViewModel.UiEvent.SaveNote -> {
navController.navigateUp()
}
}
}
}
with(sharedTransitionScope){
Scaffold(
floatingActionButton = {
FloatingActionButton(
onClick = {
viewModel.onEvent(AddEditNoteEvent.SaveNote)
},
containerColor = MaterialTheme.colorScheme.primary
){
Icon(imageVector = Icons.Default.Check , contentDescription = "Save" )
}
},
modifier = Modifier
.sharedBounds(
rememberSharedContentState(key = "note/$noteId"),
animatedVisibilityScope = animatedVisibilityScope,
enter = fadeIn(),
exit = fadeOut(),
resizeMode = SharedTransitionScope.ResizeMode.ScaleToBounds()
),
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
) { paddingValues ->
Column(
modifier = Modifier
.background(backgroundAnimateableColor.value)
.fillMaxSize()
.padding(20.dp)
.padding(paddingValues)
){
Row(modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.SpaceBetween
){
Utils.noteColors.forEach{ color ->
val colorInt = color.toArgb()
Box(
modifier = Modifier
.size(50.dp)
.shadow(15.dp, CircleShape)
.clip(CircleShape)
.background(color)
.border(
width = 3.dp,
color = if (backgroundAnimateableColor.value.toArgb() == colorInt) {
Color.Black
} else Color.Transparent,
shape = CircleShape
)
.clickable {
scope.launch {
backgroundAnimateableColor.animateTo(
targetValue = Color(colorInt),
animationSpec = tween(
delayMillis = 300
)
)
}
viewModel.onEvent(AddEditNoteEvent.ChangeColor(colorInt))
}
)
}
}
Spacer(modifier = Modifier.height(16.dp))
TrasnparentHintTextField(
text = titleState.text,
hint = titleState.hint,
onValueChange = {
viewModel.onEvent(AddEditNoteEvent.EnteredTitle(it))
},
onFocusChange = {
viewModel.onEvent(AddEditNoteEvent.IsFocusTitle(it))
},
isHintVisible = titleState.isHintVisible,
singleLine = true,
textStyle = MaterialTheme.typography.headlineSmall
)
Spacer(modifier = Modifier.height(16.dp))
TrasnparentHintTextField(
text = contentState.text,
hint = contentState.hint,
onValueChange = {
viewModel.onEvent(AddEditNoteEvent.EnteredContent(it))
},
onFocusChange = {
viewModel.onEvent(AddEditNoteEvent.IsFocusContent(it))
},
isHintVisible = contentState.isHintVisible,
singleLine = false,
textStyle = MaterialTheme.typography.bodyLarge
)
}
}
}
}
Кто-нибудь знает, как это исправить?
P.S: я думаю, это произойдет, если заметка будет перекомпонована.
Я уже пытаюсь изменить модификатор ShareElement и измените расположение модификатора
Подробнее здесь:
https://stackoverflow.com/questions/786 ... sition-bug
1719677902
Anonymous
Итак, у меня есть ошибка перехода общего элемента, или, может быть, я просто неправильно реализовал ее при компоновке, вы можете увидеть ошибку в этом видео. как вы можете видеть сначала переход между экраном списка и экраном подробностей (добавить экран редактирования) работают правильно, и после открытия (добавить экран редактирования) из FAB, чтобы добавить новую заметку, переход сломан и просто показывает, что элемент исчез, и снова появляется без перехода в режим изменения размера, как в первый раз, эта проблема также возникает, если я очень быстро ищу заметки или удаляю и отменяю удаление заметки. и это мой код Код содержимого заметки:< /p> [code] @OptIn(ExperimentalSharedTransitionApi::class) @Composable fun NoteContent( state: NoteState, query: String, onOrderChange: (NoteOrder) -> Unit, onToggleOrderSectionClick: () -> Unit, onDeleteClick: (Note) -> Unit, onUndoClick: () -> Unit, navigateToAddEdit: (Int, Int) -> Unit, onQueryChange: (String) -> Unit, sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope ) { val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() val staggeredGridState = rememberLazyStaggeredGridState() with(sharedTransitionScope){ Scaffold( floatingActionButton = { FloatingActionButton( onClick = {navigateToAddEdit(-1,-1)}, containerColor = MaterialTheme.colorScheme.primary, ) { Icon(imageVector = Icons.Default.Add, contentDescription = "Add Note") } }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, ) { padding -> Column( modifier = Modifier .fillMaxSize() .padding(horizontal = 8.dp) ) { LazyVerticalStaggeredGrid( state = staggeredGridState, columns = StaggeredGridCells.Fixed(2), modifier = Modifier.fillMaxWidth(), contentPadding = PaddingValues(bottom = 4.dp), horizontalArrangement = Arrangement.spacedBy(4.dp), verticalItemSpacing = 4.dp ) { item(span = StaggeredGridItemSpan.FullLine) { SearchBar( query = query, onQueryChange = onQueryChange, onToggleOrderSectionClick = onToggleOrderSectionClick ) } item(span = StaggeredGridItemSpan.FullLine) { AnimatedVisibility( visible = state.isOrderSectionVisible, enter = fadeIn() + slideInVertically(), exit = fadeOut() + slideOutVertically() ) { OrderRadio(modifier = Modifier .fillMaxWidth() .padding(vertical = 8.dp, horizontal = 8.dp), noteOrder = state.noteOrder, onOrderChange = { order -> onOrderChange(order) }) } } items(state.notes, key = { it.id ?: 0 }) { note -> AnimatedVisibility( visible = state.notes.isNotEmpty(), enter = fadeIn(), exit = fadeOut(), ) { NoteItem(note = note, modifier = Modifier .padding(4.dp) .fillMaxWidth() .animateItem( placementSpec = tween( durationMillis = 300, delayMillis = 0 ) ) .sharedBounds( rememberSharedContentState(key = "note/${note.id}"), animatedVisibilityScope = animatedVisibilityScope, enter = fadeIn(), exit = fadeOut(), resizeMode = SharedTransitionScope.ResizeMode.ScaleToBounds() ), // This line adds the placement animation onDeleteClick = { onDeleteClick(note) scope.launch { val result = snackbarHostState.showSnackbar( message = "Note deleted", actionLabel = "Undo" ) if (result == SnackbarResult.ActionPerformed) { onUndoClick() } } }, onClick = { note.id?.let { it1 -> navigateToAddEdit(it1, note.color) } }) } } } AnimatedVisibility( visible = state.notes.isEmpty(), enter = fadeIn(), exit = fadeOut(), ) { EmptyNote( isSearchActive = state.isSearchActive, ) } } } } } [/code] Код AddEditScreen: [code] @OptIn(ExperimentalSharedTransitionApi::class) @Composable fun AddEditNoteScreen( navController: NavController, noteColor : Int, noteId:Int?, viewModel: AddEditViewModel = hiltViewModel(), sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope ){ val titleState = viewModel.title.value val contentState = viewModel.content.value val snackbarHostState = remember { SnackbarHostState() } Log.d("test", noteColor.toString()) val backgroundAnimateableColor = remember { Animatable( Color(if (noteColor != -1) noteColor else viewModel.color.value) ) } if(noteColor != -1){ viewModel.onEvent(AddEditNoteEvent.ChangeColor(noteColor)) } val scope = rememberCoroutineScope() LaunchedEffect(key1 = true) { viewModel.eventFlow.collectLatest { event -> when (event) { is AddEditViewModel.UiEvent.ShowSnackbar -> { snackbarHostState.showSnackbar( message = event.message ) } is AddEditViewModel.UiEvent.SaveNote -> { navController.navigateUp() } } } } with(sharedTransitionScope){ Scaffold( floatingActionButton = { FloatingActionButton( onClick = { viewModel.onEvent(AddEditNoteEvent.SaveNote) }, containerColor = MaterialTheme.colorScheme.primary ){ Icon(imageVector = Icons.Default.Check , contentDescription = "Save" ) } }, modifier = Modifier .sharedBounds( rememberSharedContentState(key = "note/$noteId"), animatedVisibilityScope = animatedVisibilityScope, enter = fadeIn(), exit = fadeOut(), resizeMode = SharedTransitionScope.ResizeMode.ScaleToBounds() ), snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, ) { paddingValues -> Column( modifier = Modifier .background(backgroundAnimateableColor.value) .fillMaxSize() .padding(20.dp) .padding(paddingValues) ){ Row(modifier = Modifier .fillMaxWidth() .padding(8.dp), horizontalArrangement = Arrangement.SpaceBetween ){ Utils.noteColors.forEach{ color -> val colorInt = color.toArgb() Box( modifier = Modifier .size(50.dp) .shadow(15.dp, CircleShape) .clip(CircleShape) .background(color) .border( width = 3.dp, color = if (backgroundAnimateableColor.value.toArgb() == colorInt) { Color.Black } else Color.Transparent, shape = CircleShape ) .clickable { scope.launch { backgroundAnimateableColor.animateTo( targetValue = Color(colorInt), animationSpec = tween( delayMillis = 300 ) ) } viewModel.onEvent(AddEditNoteEvent.ChangeColor(colorInt)) } ) } } Spacer(modifier = Modifier.height(16.dp)) TrasnparentHintTextField( text = titleState.text, hint = titleState.hint, onValueChange = { viewModel.onEvent(AddEditNoteEvent.EnteredTitle(it)) }, onFocusChange = { viewModel.onEvent(AddEditNoteEvent.IsFocusTitle(it)) }, isHintVisible = titleState.isHintVisible, singleLine = true, textStyle = MaterialTheme.typography.headlineSmall ) Spacer(modifier = Modifier.height(16.dp)) TrasnparentHintTextField( text = contentState.text, hint = contentState.hint, onValueChange = { viewModel.onEvent(AddEditNoteEvent.EnteredContent(it)) }, onFocusChange = { viewModel.onEvent(AddEditNoteEvent.IsFocusContent(it)) }, isHintVisible = contentState.isHintVisible, singleLine = false, textStyle = MaterialTheme.typography.bodyLarge ) } } } } [/code] Кто-нибудь знает, как это исправить? P.S: я думаю, это произойдет, если заметка будет перекомпонована. Я уже пытаюсь изменить модификатор ShareElement и измените расположение модификатора Подробнее здесь: [url]https://stackoverflow.com/questions/78686535/jetpack-compose-shared-element-transition-bug[/url]