fix: enhance avatar expansion and snapping behavior for smoother interactions
This commit is contained in:
@@ -546,51 +546,51 @@ fun ProfileMetaballOverlay(
|
||||
val avatarCenterY = avatarState.centerY
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// UNIFIED SCALE для всех режимов:
|
||||
// - Normal (expansion=0, collapse=0): scale = 1.0
|
||||
// - Expansion (expansion>0): scale растёт до screenWidth/baseSizePx
|
||||
// - Collapse (collapse>0): scale = avatarState.radius * 2 / baseSizePx
|
||||
// 🔥 UNIFIED SCALE - БЕЗ резких переключений when
|
||||
// Всегда вычисляем scale на основе avatarState.radius
|
||||
// При expansion - дополнительно интерполируем к screenWidth
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
val uniformScale: Float
|
||||
val currentCenterX: Float
|
||||
val currentCenterY: Float
|
||||
val cornerRadiusPx: Float
|
||||
val applyBlur: Boolean
|
||||
|
||||
when {
|
||||
expansionProgress > 0f -> {
|
||||
// EXPANSION MODE
|
||||
val targetSize = screenWidthPx
|
||||
uniformScale = lerpFloat(1f, targetSize / baseSizePx, expansionProgress)
|
||||
|
||||
// Центр смещается к центру header
|
||||
val targetCenterX = screenWidthPx / 2f
|
||||
val targetCenterY = headerHeightPx / 2f
|
||||
currentCenterX = lerpFloat(avatarCenterX, targetCenterX, expansionProgress)
|
||||
currentCenterY = lerpFloat(avatarCenterY, targetCenterY, expansionProgress)
|
||||
|
||||
// Corner radius: круг → квадрат
|
||||
cornerRadiusPx = lerpFloat(baseSizePx / 2f, 0f, expansionProgress)
|
||||
applyBlur = false
|
||||
}
|
||||
collapseProgress > 0f -> {
|
||||
// COLLAPSE MODE - используем avatarState.radius через scale
|
||||
uniformScale = (avatarState.radius * 2f) / baseSizePx
|
||||
currentCenterX = avatarCenterX
|
||||
currentCenterY = avatarCenterY
|
||||
// cornerRadius нужен относительно BASE size, поэтому делим на scale
|
||||
cornerRadiusPx = avatarState.cornerRadius / uniformScale
|
||||
applyBlur = avatarState.blurRadius > 0.5f
|
||||
}
|
||||
else -> {
|
||||
// NORMAL MODE
|
||||
uniformScale = 1f
|
||||
currentCenterX = avatarCenterX
|
||||
currentCenterY = avatarCenterY
|
||||
cornerRadiusPx = baseSizePx / 2f // Полный круг
|
||||
applyBlur = false
|
||||
}
|
||||
// Базовый scale из avatarState.radius (работает для collapse И normal)
|
||||
val baseScale = (avatarState.radius * 2f) / baseSizePx
|
||||
|
||||
// При expansion: дополнительно масштабируем к screenWidth
|
||||
val targetExpansionScale = screenWidthPx / baseSizePx
|
||||
val uniformScale = if (expansionProgress > 0f) {
|
||||
// Плавный переход от baseScale к targetExpansionScale
|
||||
lerpFloat(baseScale, targetExpansionScale, expansionProgress)
|
||||
} else {
|
||||
baseScale
|
||||
}.coerceAtLeast(0.01f) // Защита от деления на 0
|
||||
|
||||
// Центр: при expansion двигается к центру header
|
||||
val targetCenterX = screenWidthPx / 2f
|
||||
val targetCenterY = headerHeightPx / 2f
|
||||
val currentCenterX = if (expansionProgress > 0f) {
|
||||
lerpFloat(avatarCenterX, targetCenterX, expansionProgress)
|
||||
} else {
|
||||
avatarCenterX
|
||||
}
|
||||
val currentCenterY = if (expansionProgress > 0f) {
|
||||
lerpFloat(avatarCenterY, targetCenterY, expansionProgress)
|
||||
} else {
|
||||
avatarCenterY
|
||||
}
|
||||
|
||||
// Corner radius: для base size (120dp)
|
||||
// В normal/collapse: из avatarState, но пересчитанный для base size
|
||||
// При expansion: круг → квадрат
|
||||
val cornerRadiusPx: Float = if (expansionProgress > 0f) {
|
||||
// Expansion: плавно круг → квадрат
|
||||
lerpFloat(baseSizePx / 2f, 0f, expansionProgress)
|
||||
} else {
|
||||
// Normal/Collapse: используем avatarState.cornerRadius
|
||||
// Пересчитываем для base size: cornerRadius_base = cornerRadius_current / baseScale
|
||||
(avatarState.cornerRadius / baseScale).coerceAtMost(baseSizePx / 2f)
|
||||
}
|
||||
|
||||
// Blur только при collapse близко к notch
|
||||
val applyBlur = expansionProgress == 0f && avatarState.blurRadius > 0.5f
|
||||
|
||||
// Offset: Box имеет ФИКСИРОВАННЫЙ размер, scale применяется от центра
|
||||
val offsetX = with(density) { (currentCenterX - baseSizePx / 2f).toDp() }
|
||||
@@ -698,37 +698,34 @@ fun ProfileMetaballOverlayCompat(
|
||||
val avatarCenterX = avatarState.centerX
|
||||
val avatarCenterY = avatarState.centerY
|
||||
|
||||
// UNIFIED SCALE для всех режимов
|
||||
val uniformScale: Float
|
||||
val currentCenterX: Float
|
||||
val currentCenterY: Float
|
||||
val cornerRadiusPx: Float
|
||||
// 🔥 UNIFIED SCALE - БЕЗ резких переключений when
|
||||
val baseScale = (avatarState.radius * 2f) / baseSizePx
|
||||
val targetExpansionScale = screenWidthPx / baseSizePx
|
||||
val uniformScale = if (expansionProgress > 0f) {
|
||||
lerpFloat(baseScale, targetExpansionScale, expansionProgress)
|
||||
} else {
|
||||
baseScale
|
||||
}.coerceAtLeast(0.01f)
|
||||
|
||||
when {
|
||||
expansionProgress > 0f -> {
|
||||
// EXPANSION MODE
|
||||
val targetSize = screenWidthPx
|
||||
uniformScale = lerpFloat(1f, targetSize / baseSizePx, expansionProgress)
|
||||
val targetCenterX = screenWidthPx / 2f
|
||||
val targetCenterY = headerHeightPx / 2f
|
||||
currentCenterX = lerpFloat(avatarCenterX, targetCenterX, expansionProgress)
|
||||
currentCenterY = lerpFloat(avatarCenterY, targetCenterY, expansionProgress)
|
||||
cornerRadiusPx = lerpFloat(baseSizePx / 2f, 0f, expansionProgress)
|
||||
}
|
||||
collapseProgress > 0f -> {
|
||||
// COLLAPSE MODE - используем avatarState.radius через scale
|
||||
uniformScale = (avatarState.radius * 2f) / baseSizePx
|
||||
currentCenterX = avatarCenterX
|
||||
currentCenterY = avatarCenterY
|
||||
cornerRadiusPx = avatarState.cornerRadius / uniformScale
|
||||
}
|
||||
else -> {
|
||||
// NORMAL MODE
|
||||
uniformScale = 1f
|
||||
currentCenterX = avatarCenterX
|
||||
currentCenterY = avatarCenterY
|
||||
cornerRadiusPx = baseSizePx / 2f
|
||||
}
|
||||
// Центр: при expansion двигается к центру header
|
||||
val targetCenterX = screenWidthPx / 2f
|
||||
val targetCenterY = headerHeightPx / 2f
|
||||
val currentCenterX = if (expansionProgress > 0f) {
|
||||
lerpFloat(avatarCenterX, targetCenterX, expansionProgress)
|
||||
} else {
|
||||
avatarCenterX
|
||||
}
|
||||
val currentCenterY = if (expansionProgress > 0f) {
|
||||
lerpFloat(avatarCenterY, targetCenterY, expansionProgress)
|
||||
} else {
|
||||
avatarCenterY
|
||||
}
|
||||
|
||||
// Corner radius
|
||||
val cornerRadiusPx: Float = if (expansionProgress > 0f) {
|
||||
lerpFloat(baseSizePx / 2f, 0f, expansionProgress)
|
||||
} else {
|
||||
(avatarState.cornerRadius / baseScale).coerceAtMost(baseSizePx / 2f)
|
||||
}
|
||||
|
||||
val offsetX = with(density) { (currentCenterX - baseSizePx / 2f).toDp() }
|
||||
|
||||
Reference in New Issue
Block a user