Anonymous
Jetpack Compose TopBar поднимается вверх на клавиатуре
Сообщение
Anonymous » 26 апр 2024, 07:48
У меня есть проект KMM с общим пользовательским интерфейсом.
У меня есть экран чата, на котором есть верхняя панель с информацией о чате, списком сообщений и полем ввода для написания новых сообщений. p>
Моя проблема заключается в том, что при появлении клавиатуры все содержимое поднимается вверх, включая TopAppBar.
И я хочу, чтобы изменялся только размер LazyColumn и закреплялся TopBar.
Конечно, в моем манифесте для AndroidApp есть android:windowSoftInputMode="adjustResize".
Код приведен ниже
Код: Выделить всё
Scaffold(
modifier = Modifier
.statusBarsPadding()
.fillMaxWidth()
.background(Color.White)
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
TopAppBar(
modifier = Modifier
.fillMaxWidth()
.requiredHeight(56.dp)
.background(Color.White),
title = {
Row(
modifier = Modifier
.fillMaxWidth()
.requiredHeight(56.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
modifier = Modifier.height(44.dp).width(44.dp).clickable(enabled = true) {
component.onEvent(ChatRoomEvents.BackClick)
},
contentScale = ContentScale.None,
painter = painterResource(Res.drawable.back_green),
contentDescription = Strings.getString("back")
)
SeafarerImage(
modifier = chatRoomImageModifier,
picture = component.chatRoom.pic,
placeHolder = if (component.chatRoom.isSupport) Res.drawable.nextship_logo_short else Res.drawable.empty_seafarer_chat
)
Column(
modifier = Modifier.weight(1f).height(41.dp).padding(start = 8.dp)
) {
Text(
modifier = Modifier.height(19.dp),
text = component.chatRoom.userName ?: "",
textAlign = TextAlign.Start,
style = getTypography().subtitle1,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Text(
modifier = Modifier.height(19.dp),
text = "last seen recently", // TODO time
textAlign = TextAlign.Start,
style = getTypography().subtitle2,
fontSize = 13.sp,
color = lightGreen,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
Image(
modifier = Modifier.height(44.dp).width(44.dp).clickable(enabled = true) {
component.onEvent(ChatRoomEvents.SendMessage)
},
contentScale = ContentScale.None,
painter = painterResource(Res.drawable.trash),
contentDescription = Strings.getString("delete_chat")
)
Spacer(Modifier.width(6.dp))
}
}
)
},
content = { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
.background(brush),
state = listState,
reverseLayout = true
) {
item {
if (screenState.isLoading) ProgressIndicator()
}
items(
count = messages.size
) { index ->
ChatItem(messages[index], component.dateFormat)
}
}
if (!listState.isScrollInProgress) {
if (!listState.canScrollForward && listState.canScrollBackward && component.needNextPage)
component.getNextPage()
}
CommentRow(modifier = Modifier.fillMaxWidth(),
interactionSource = commentInteractionSource,
currentText = screenState.messageText ?: "",
sendEnabled = true,//!screenState.isLoading && screenState.currentText?.isNotEmpty() == true,
onTextChange = { newText -> component.onEvent(ChatRoomEvents.MessageTextChanged(newText)) },
onSendClick = { component.onEvent(ChatRoomEvents.SendMessage) }
)
}
}
)
строка комментариев:
Код: Выделить всё
@OptIn(ExperimentalResourceApi::class)
@Composable
fun CommentRow(
modifier: Modifier,
interactionSource: MutableInteractionSource,
currentText: String,
sendEnabled: Boolean,
onTextChange: (String) -> Unit,
onSendClick: () -> Unit,
) {
Row(
modifier = modifier
.wrapContentHeight()
.navigationBarsPadding()
.background(Color.White)
) {
BasicTextField(
modifier = Modifier
.weight(1f)
.heightIn(50.dp, 100.dp)
.background(Color.White)
.padding(start = 20.dp, top = 10.dp, bottom = 10.dp),
interactionSource = interactionSource,
textStyle = getTypography().subtitle2,
value = currentText,
onValueChange = { newText -> onTextChange(newText) },
maxLines = 3,
)
Spacer(Modifier.width(10.dp))
Box(
modifier = Modifier
.width(48.dp)
) {
Image(
modifier = Modifier
.height(26.dp)
.width(26.dp)
.offset(y = 13.dp)
.clickable(enabled = sendEnabled) { onSendClick() },
painter = painterResource(if (sendEnabled) Res.drawable.send_message else Res.drawable.send_message_disabled),
contentDescription = Strings.getString("send_message")
)
}
}
}
Моя основная деятельность выглядит так:
Я использую библиотеку Decompose для навигации
Код: Выделить всё
MaterialTheme {
val childStack by root.childStack.subscribeAsState()
Scaffold(
modifier = Modifier.fillMaxSize().background(mainTextColor),
) {
Column(
modifier = Modifier
.fillMaxHeight()
.background(mainTextColor),
) {
var showBottomBar = false
Children(
modifier = Modifier.fillMaxSize().weight(1F),
stack = childStack
) { child ->
when (val instance = child.instance) {
is RootComponent.Child.NoInternetChild -> {
InternetErrorScreen(instance.component)
}
is RootComponent.Child.SplashChild -> SplashScreen()
is RootComponent.Child.AuthChild -> AuthStart(instance.component)
is RootComponent.Child.PasswordRecoveryChild -> RecoverPassword(instance.component)
is RootComponent.Child.NewPasswordChild -> NewPassword(instance.component)
is RootComponent.Child.SearchChild -> {
showBottomBar = true
SearchScreen(instance.component)
}
is RootComponent.Child.SeafarerProfileChild -> SeafarerDataScreen(instance.component)
is RootComponent.Child.GeneralDataChild -> GeneralDataScreen(instance.component)
is RootComponent.Child.ContactsChild -> SeafarerContactsScreen(instance.component)
is RootComponent.Child.WorkExperienceChild -> WorkExperienceScreen(instance.component)
is RootComponent.Child.DocsChild -> DocsScreen(instance.component)
is RootComponent.Child.ChatChild -> {
showBottomBar = true
ChatRoomsScreen(instance.component)
}
is RootComponent.Child.MainChild -> {
showBottomBar = true
MainScreen(instance.component)
}
is RootComponent.Child.StatsChild -> TODO()
is RootComponent.Child.SeafarerDocumentsChild -> DocumentsScreen(instance.component)
is RootComponent.Child.BiometricsChild -> BiometricsScreen(instance.component)
is RootComponent.Child.VideoResumeChild -> VideoResumeScreen(instance.component)
is RootComponent.Child.ReviewsChild -> ReviewsScreen(instance.component)
is RootComponent.Child.ColleaguesChild -> ColleaguesScreen(instance.component)
is RootComponent.Child.CommentsChild -> CommentsScreen(instance.component)
is RootComponent.Child.VacancyChild -> VacancyInfoScreen(instance.component)
is RootComponent.Child.SettingsChild -> SettingsScreen(instance.component)
is RootComponent.Child.ChatRoomChild -> ChatRoomScreen(instance.component)
}
}
if (showBottomBar) {
BottomBar(
root,
Modifier
.fillMaxWidth()
.navigationBarsPadding()
)
}
}
}
}
Нет клавиатуры
Клавиатура
Я хочу, чтобы верхняя панель была зафиксирована на экране
Подробнее здесь:
https://stackoverflow.com/questions/783 ... board-show
1714106881
Anonymous
У меня есть проект KMM с общим пользовательским интерфейсом. У меня есть экран чата, на котором есть верхняя панель с информацией о чате, списком сообщений и полем ввода для написания новых сообщений. p> Моя проблема заключается в том, что при появлении клавиатуры все содержимое поднимается вверх, включая TopAppBar. И я хочу, чтобы изменялся только размер LazyColumn и закреплялся TopBar. Конечно, в моем манифесте для AndroidApp есть android:windowSoftInputMode="adjustResize". Код приведен ниже [code]Scaffold( modifier = Modifier .statusBarsPadding() .fillMaxWidth() .background(Color.White) .nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { TopAppBar( modifier = Modifier .fillMaxWidth() .requiredHeight(56.dp) .background(Color.White), title = { Row( modifier = Modifier .fillMaxWidth() .requiredHeight(56.dp), verticalAlignment = Alignment.CenterVertically ) { Image( modifier = Modifier.height(44.dp).width(44.dp).clickable(enabled = true) { component.onEvent(ChatRoomEvents.BackClick) }, contentScale = ContentScale.None, painter = painterResource(Res.drawable.back_green), contentDescription = Strings.getString("back") ) SeafarerImage( modifier = chatRoomImageModifier, picture = component.chatRoom.pic, placeHolder = if (component.chatRoom.isSupport) Res.drawable.nextship_logo_short else Res.drawable.empty_seafarer_chat ) Column( modifier = Modifier.weight(1f).height(41.dp).padding(start = 8.dp) ) { Text( modifier = Modifier.height(19.dp), text = component.chatRoom.userName ?: "", textAlign = TextAlign.Start, style = getTypography().subtitle1, maxLines = 1, overflow = TextOverflow.Ellipsis ) Text( modifier = Modifier.height(19.dp), text = "last seen recently", // TODO time textAlign = TextAlign.Start, style = getTypography().subtitle2, fontSize = 13.sp, color = lightGreen, maxLines = 1, overflow = TextOverflow.Ellipsis ) } Image( modifier = Modifier.height(44.dp).width(44.dp).clickable(enabled = true) { component.onEvent(ChatRoomEvents.SendMessage) }, contentScale = ContentScale.None, painter = painterResource(Res.drawable.trash), contentDescription = Strings.getString("delete_chat") ) Spacer(Modifier.width(6.dp)) } } ) }, content = { innerPadding -> Column( modifier = Modifier .fillMaxSize() .padding(innerPadding) ) { LazyColumn( modifier = Modifier .fillMaxWidth() .weight(1f) .background(brush), state = listState, reverseLayout = true ) { item { if (screenState.isLoading) ProgressIndicator() } items( count = messages.size ) { index -> ChatItem(messages[index], component.dateFormat) } } if (!listState.isScrollInProgress) { if (!listState.canScrollForward && listState.canScrollBackward && component.needNextPage) component.getNextPage() } CommentRow(modifier = Modifier.fillMaxWidth(), interactionSource = commentInteractionSource, currentText = screenState.messageText ?: "", sendEnabled = true,//!screenState.isLoading && screenState.currentText?.isNotEmpty() == true, onTextChange = { newText -> component.onEvent(ChatRoomEvents.MessageTextChanged(newText)) }, onSendClick = { component.onEvent(ChatRoomEvents.SendMessage) } ) } } ) [/code] строка комментариев: [code]@OptIn(ExperimentalResourceApi::class) @Composable fun CommentRow( modifier: Modifier, interactionSource: MutableInteractionSource, currentText: String, sendEnabled: Boolean, onTextChange: (String) -> Unit, onSendClick: () -> Unit, ) { Row( modifier = modifier .wrapContentHeight() .navigationBarsPadding() .background(Color.White) ) { BasicTextField( modifier = Modifier .weight(1f) .heightIn(50.dp, 100.dp) .background(Color.White) .padding(start = 20.dp, top = 10.dp, bottom = 10.dp), interactionSource = interactionSource, textStyle = getTypography().subtitle2, value = currentText, onValueChange = { newText -> onTextChange(newText) }, maxLines = 3, ) Spacer(Modifier.width(10.dp)) Box( modifier = Modifier .width(48.dp) ) { Image( modifier = Modifier .height(26.dp) .width(26.dp) .offset(y = 13.dp) .clickable(enabled = sendEnabled) { onSendClick() }, painter = painterResource(if (sendEnabled) Res.drawable.send_message else Res.drawable.send_message_disabled), contentDescription = Strings.getString("send_message") ) } } } [/code] Моя основная деятельность выглядит так: Я использую библиотеку Decompose для навигации [code]MaterialTheme { val childStack by root.childStack.subscribeAsState() Scaffold( modifier = Modifier.fillMaxSize().background(mainTextColor), ) { Column( modifier = Modifier .fillMaxHeight() .background(mainTextColor), ) { var showBottomBar = false Children( modifier = Modifier.fillMaxSize().weight(1F), stack = childStack ) { child -> when (val instance = child.instance) { is RootComponent.Child.NoInternetChild -> { InternetErrorScreen(instance.component) } is RootComponent.Child.SplashChild -> SplashScreen() is RootComponent.Child.AuthChild -> AuthStart(instance.component) is RootComponent.Child.PasswordRecoveryChild -> RecoverPassword(instance.component) is RootComponent.Child.NewPasswordChild -> NewPassword(instance.component) is RootComponent.Child.SearchChild -> { showBottomBar = true SearchScreen(instance.component) } is RootComponent.Child.SeafarerProfileChild -> SeafarerDataScreen(instance.component) is RootComponent.Child.GeneralDataChild -> GeneralDataScreen(instance.component) is RootComponent.Child.ContactsChild -> SeafarerContactsScreen(instance.component) is RootComponent.Child.WorkExperienceChild -> WorkExperienceScreen(instance.component) is RootComponent.Child.DocsChild -> DocsScreen(instance.component) is RootComponent.Child.ChatChild -> { showBottomBar = true ChatRoomsScreen(instance.component) } is RootComponent.Child.MainChild -> { showBottomBar = true MainScreen(instance.component) } is RootComponent.Child.StatsChild -> TODO() is RootComponent.Child.SeafarerDocumentsChild -> DocumentsScreen(instance.component) is RootComponent.Child.BiometricsChild -> BiometricsScreen(instance.component) is RootComponent.Child.VideoResumeChild -> VideoResumeScreen(instance.component) is RootComponent.Child.ReviewsChild -> ReviewsScreen(instance.component) is RootComponent.Child.ColleaguesChild -> ColleaguesScreen(instance.component) is RootComponent.Child.CommentsChild -> CommentsScreen(instance.component) is RootComponent.Child.VacancyChild -> VacancyInfoScreen(instance.component) is RootComponent.Child.SettingsChild -> SettingsScreen(instance.component) is RootComponent.Child.ChatRoomChild -> ChatRoomScreen(instance.component) } } if (showBottomBar) { BottomBar( root, Modifier .fillMaxWidth() .navigationBarsPadding() ) } } } } [/code] Нет клавиатуры Клавиатура [img]https://i.stack.imgur.com/3NuHz.png[/img] [img] https://i.stack.imgur.com/LgKOC.png[/img] Я хочу, чтобы верхняя панель была зафиксирована на экране Подробнее здесь: [url]https://stackoverflow.com/questions/78376557/jetpack-compose-topbar-is-pushed-up-on-keyboard-show[/url]