mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-08 23:54:39 +00:00
perf: animate swipe-to-reply icon in the layer phase, not composition
The reply icon's fade/scale read dragOffset in composition, and because Box is an inline composable that read invalidated the whole ChatBubbleLayout on every drag and settle frame. Gate the icon on a derivedStateOf boolean that flips only at the 0<->non-0 edges (icon added/removed twice per gesture) and move the progress math into the icon's graphicsLayer block so it's read in the layer phase. The bubble translation was already deferred; now the entire swipe and settle animate with zero recomposition. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016f7dTu8RoJRXjnHM7FKAE2
This commit is contained in:
+8
-2
@@ -50,6 +50,7 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -192,13 +193,18 @@ fun ChatBubbleLayout(
|
||||
},
|
||||
) {
|
||||
if (onSwipeReply != null) {
|
||||
val progress = (abs(dragOffset) / swipeThresholdPx).coerceIn(0f, 1f)
|
||||
if (progress > 0f) {
|
||||
// Gate composition on a boolean that flips only at the 0<->non-0 edges, so
|
||||
// the icon is added/removed twice per gesture instead of recomposing every
|
||||
// frame; the fade/scale reads dragOffset inside graphicsLayer (layer phase),
|
||||
// so the whole swipe animates without recomposing ChatBubbleLayout.
|
||||
val swiping by remember { derivedStateOf { dragOffset != 0f } }
|
||||
if (swiping) {
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
.align(if (isLoggedInUser) Alignment.CenterEnd else Alignment.CenterStart)
|
||||
.graphicsLayer {
|
||||
val progress = (abs(dragOffset) / swipeThresholdPx).coerceIn(0f, 1f)
|
||||
alpha = progress
|
||||
scaleX = 0.6f + 0.4f * progress
|
||||
scaleY = 0.6f + 0.4f * progress
|
||||
|
||||
Reference in New Issue
Block a user