feat: Remove animation for emoji picker when keyboard opens and optimize height handling
This commit is contained in:
@@ -2298,73 +2298,49 @@ private fun MessageInputBar(
|
||||
} // Закрытие внешней Column с border
|
||||
} // End of else (not blocked)
|
||||
|
||||
// <20> APPLE EMOJI PICKER - ОПТИМИЗИРОВАННАЯ АНИМАЦИЯ
|
||||
// Используем slide up + alpha вместо height анимации (нет relayout = супер плавно)
|
||||
|
||||
// 🔥 APPLE EMOJI PICKER - БЕЗ анимации когда клавиатура открывается
|
||||
if (!isBlocked) {
|
||||
// Панель ВСЕГДА в DOM (pre-render), просто скрыта через offset/alpha
|
||||
val shouldShow = showEmojiPicker && !isKeyboardVisible
|
||||
// Высота панели: 0 если клавиатура видна или эмодзи закрыты, иначе emojiPanelHeight
|
||||
val targetHeight = if (isKeyboardVisible || !showEmojiPicker) 0.dp else emojiPanelHeight
|
||||
|
||||
// 🚀 Animatable для максимального контроля (быстрее чем animateDpAsState)
|
||||
val slideProgress = remember { Animatable(0f) }
|
||||
|
||||
LaunchedEffect(shouldShow) {
|
||||
if (shouldShow) {
|
||||
// Открытие: быстрая spring анимация (critically damped = без пружинистости)
|
||||
slideProgress.animateTo(
|
||||
targetValue = 1f,
|
||||
animationSpec = spring(
|
||||
dampingRatio = 1f, // Critically damped - без bounce
|
||||
stiffness = 800f // Высокая жёсткость = быстро
|
||||
)
|
||||
)
|
||||
// Анимируем только когда клавиатура закрыта
|
||||
val animatedHeight by animateDpAsState(
|
||||
targetValue = targetHeight,
|
||||
animationSpec = if (isKeyboardVisible) {
|
||||
// Мгновенно когда клавиатура открывается
|
||||
snap()
|
||||
} else {
|
||||
// Закрытие: мгновенно если клавиатура открылась, иначе быстрая анимация
|
||||
if (isKeyboardVisible) {
|
||||
slideProgress.snapTo(0f)
|
||||
} else {
|
||||
slideProgress.animateTo(
|
||||
targetValue = 0f,
|
||||
animationSpec = tween(120, easing = FastOutSlowInEasing)
|
||||
// Быстрая анимация (200ms)
|
||||
tween(durationMillis = 200, easing = FastOutSlowInEasing)
|
||||
},
|
||||
label = "EmojiPanelHeight"
|
||||
)
|
||||
|
||||
// 🔥 Показываем Box только когда есть высота (НЕ занимает место когда скрыт!)
|
||||
if (animatedHeight > 0.dp) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(animatedHeight)
|
||||
.padding(bottom = 16.dp)
|
||||
) {
|
||||
if (showEmojiPicker) {
|
||||
AppleEmojiPickerPanel(
|
||||
isDarkTheme = isDarkTheme,
|
||||
onEmojiSelected = { emoji ->
|
||||
onValueChange(value + emoji)
|
||||
},
|
||||
onClose = {
|
||||
onToggleEmojiPicker(false)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(emojiPanelHeight - 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val panelHeightPx = with(LocalDensity.current) { (emojiPanelHeight - 16.dp).toPx() }
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(emojiPanelHeight)
|
||||
.padding(bottom = 16.dp)
|
||||
.graphicsLayer {
|
||||
// 🚀 Slide up анимация через translationY (НЕ вызывает relayout!)
|
||||
translationY = panelHeightPx * (1f - slideProgress.value)
|
||||
alpha = slideProgress.value
|
||||
// Hardware layer для плавности
|
||||
if (slideProgress.value > 0f && slideProgress.value < 1f) {
|
||||
shadowElevation = 0f
|
||||
}
|
||||
}
|
||||
.clipToBounds() // Обрезаем контент при slide
|
||||
) {
|
||||
// 🚀 Панель ВСЕГДА рендерится (pre-render для instant open)
|
||||
// Но скрыта через alpha = 0 когда не нужна
|
||||
if (slideProgress.value > 0f || shouldShow) {
|
||||
AppleEmojiPickerPanel(
|
||||
isDarkTheme = isDarkTheme,
|
||||
onEmojiSelected = { emoji ->
|
||||
onValueChange(value + emoji)
|
||||
},
|
||||
onClose = {
|
||||
onToggleEmojiPicker(false)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(emojiPanelHeight - 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
} // End of if (!isBlocked) for emoji picker
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user