diff --git a/app/src/main/java/com/aiosman/riderpro/ui/chat/ChatScreen.kt b/app/src/main/java/com/aiosman/riderpro/ui/chat/ChatScreen.kt index 79ffaf5..618bb22 100644 --- a/app/src/main/java/com/aiosman/riderpro/ui/chat/ChatScreen.kt +++ b/app/src/main/java/com/aiosman/riderpro/ui/chat/ChatScreen.kt @@ -1,10 +1,13 @@ package com.aiosman.riderpro.ui.chat +import android.view.KeyEvent import androidx.compose.animation.Crossfade +import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -14,6 +17,7 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding @@ -23,6 +27,8 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Scaffold import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -37,11 +43,19 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.key.onKeyEvent +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.platform.SoftwareKeyboardController import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.ViewModel @@ -52,6 +66,7 @@ import com.aiosman.riderpro.R import com.aiosman.riderpro.ui.composables.CustomAsyncImage import com.aiosman.riderpro.ui.composables.StatusBarSpacer import com.aiosman.riderpro.ui.modifiers.noRippleClickable +import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -146,11 +161,6 @@ fun ChatScreen(userId: String) { ChatInput() { viewModel.sendMessage(it, context) } - Box( - modifier = Modifier - .fillMaxWidth() - .height(navigationBarHeight) - ) } } ) { paddingValues -> @@ -320,20 +330,46 @@ fun ChatItem(item: ChatItem, currentUserId: String) { fun ChatInput( onSend: (String) -> Unit = {} ) { + val navigationBarHeight = with(LocalDensity.current) { + WindowInsets.navigationBars.getBottom(this).toDp() + } + var keyboardController by remember { mutableStateOf(null) } + var isKeyboardOpen by remember { mutableStateOf(false) } var text by remember { mutableStateOf("") } + val inputBarHeight by animateDpAsState( + targetValue = if (isKeyboardOpen) 8.dp else navigationBarHeight, + animationSpec = tween(durationMillis = 300), label = "" + ) + + // 在 isKeyboardOpen 变化时立即更新 inputBarHeight 的动画目标值 + LaunchedEffect(isKeyboardOpen) { + inputBarHeight // 触发 inputBarHeight 的重组 + } + val focusManager = LocalFocusManager.current + val windowInsets = WindowInsets.ime + val density = LocalDensity.current + val softwareKeyboardController = LocalSoftwareKeyboardController.current + val currentDensity by rememberUpdatedState(density) + + LaunchedEffect(windowInsets.getBottom(currentDensity)) { + if (windowInsets.getBottom(currentDensity) <= 0) { + focusManager.clearFocus() + } + } + Row( modifier = Modifier .fillMaxWidth() - .padding(vertical = 8.dp, horizontal = 16.dp) + .padding(horizontal = 16.dp) + .padding(bottom = inputBarHeight) ) { Box( modifier = Modifier .weight(1f) - .clip(androidx.compose.foundation.shape.RoundedCornerShape(16.dp)) + .clip(RoundedCornerShape(16.dp)) .background(Color(0xffe5e5e5)) .padding(horizontal = 16.dp), contentAlignment = androidx.compose.ui.Alignment.CenterStart - ) { BasicTextField( value = text, @@ -347,7 +383,23 @@ fun ChatInput( modifier = Modifier .fillMaxWidth() .padding(vertical = 8.dp) - + .onFocusChanged { focusState -> + isKeyboardOpen = focusState.isFocused + } + .pointerInput(Unit) { + awaitPointerEventScope { + keyboardController = softwareKeyboardController + awaitFirstDown().also { + keyboardController?.show() + } + } + }, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions( + onDone = { + keyboardController?.hide() + } + ) ) } Spacer(modifier = Modifier.width(16.dp))