聊天界面键盘底部Padding动画
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
package com.aiosman.riderpro.ui.chat
|
package com.aiosman.riderpro.ui.chat
|
||||||
|
|
||||||
|
import android.view.KeyEvent
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
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.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.ime
|
||||||
import androidx.compose.foundation.layout.imePadding
|
import androidx.compose.foundation.layout.imePadding
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
import androidx.compose.foundation.layout.padding
|
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.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
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.Scaffold
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -37,11 +43,19 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.Color
|
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.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.res.painterResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.lifecycle.ViewModel
|
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.CustomAsyncImage
|
||||||
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
@@ -146,11 +161,6 @@ fun ChatScreen(userId: String) {
|
|||||||
ChatInput() {
|
ChatInput() {
|
||||||
viewModel.sendMessage(it, context)
|
viewModel.sendMessage(it, context)
|
||||||
}
|
}
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(navigationBarHeight)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
@@ -320,20 +330,46 @@ fun ChatItem(item: ChatItem, currentUserId: String) {
|
|||||||
fun ChatInput(
|
fun ChatInput(
|
||||||
onSend: (String) -> Unit = {}
|
onSend: (String) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
|
val navigationBarHeight = with(LocalDensity.current) {
|
||||||
|
WindowInsets.navigationBars.getBottom(this).toDp()
|
||||||
|
}
|
||||||
|
var keyboardController by remember { mutableStateOf<SoftwareKeyboardController?>(null) }
|
||||||
|
var isKeyboardOpen by remember { mutableStateOf(false) }
|
||||||
var text by remember { mutableStateOf("") }
|
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(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp, horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
|
.padding(bottom = inputBarHeight)
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.clip(androidx.compose.foundation.shape.RoundedCornerShape(16.dp))
|
.clip(RoundedCornerShape(16.dp))
|
||||||
.background(Color(0xffe5e5e5))
|
.background(Color(0xffe5e5e5))
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
contentAlignment = androidx.compose.ui.Alignment.CenterStart
|
contentAlignment = androidx.compose.ui.Alignment.CenterStart
|
||||||
|
|
||||||
) {
|
) {
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = text,
|
value = text,
|
||||||
@@ -347,7 +383,23 @@ fun ChatInput(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp)
|
.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))
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|||||||
Reference in New Issue
Block a user