{"id":45738,"date":"2021-11-20T11:16:18","date_gmt":"2021-11-20T02:16:18","guid":{"rendered":"https:\/\/www.charlezz.com\/?p=45738"},"modified":"2021-11-20T11:16:19","modified_gmt":"2021-11-20T02:16:19","slug":"jetpack-compose-animation-%ec%a0%9c%ec%8a%a4%ec%b3%90-%ec%95%a0%eb%8b%88%eb%a9%94%ec%9d%b4%ec%85%98","status":"publish","type":"post","link":"https:\/\/charlezz.com\/?p=45738","title":{"rendered":"Jetpack Compose Animation &#8211; \uc81c\uc2a4\uccd0 \uc560\ub2c8\uba54\uc774\uc158"},"content":{"rendered":"\n<p>\uc774 \ub9c8\uc9c0\ub9c9 \uc139\uc158\uc5d0\uc11c\ub294 \ud130\uce58 \uc785\ub825\uc744 \uae30\ubc18\uc73c\ub85c \uc560\ub2c8\uba54\uc774\uc158\uc744 \uc2e4\ud589\ud558\ub294 \ubc29\ubc95\uc5d0 \ub300\ud574 \uc54c\uc544\ubcf4\uc790. \uc774 \uc2dc\ub098\ub9ac\uc624\uc5d0\uc11c \uace0\ub824\ud574\uc57c \ud560 \uba87 \uac00\uc9c0 \uace0\uc720\ud55c \uc0ac\ud56d\uc774 \uc788\ub2e4. \uccab\uc9f8, \uc9c4\ud589 \uc911\uc778 \uc560\ub2c8\uba54\uc774\uc158\uc774 \ud130\uce58 \uc774\ubca4\ud2b8\uc5d0 \uc758\ud574 \uac00\ub85c\ucc4c \uc218 \uc788\ub2e4. \ub458\uc9f8, \uc560\ub2c8\uba54\uc774\uc158 \uac12\uc774 \uc720\uc77c\ud55c \uc815\ubcf4 \uc18c\uc2a4\uac00 \uc544\ub2d0 \uc218\ub3c4 \uc788\ub2e4. \uc989, \uc560\ub2c8\uba54\uc774\uc158 \uac12\uc744 \ud130\uce58 \uc774\ubca4\ud2b8\uc5d0\uc11c \uc624\ub294 \uac12\uacfc \ub3d9\uae30\ud654\ud574\uc57c \ud560 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<p>swipeToDismiss Modifier\uc5d0\uc11c TODO 6-1\uc744 \ucc3e\uc790. \uc5ec\uae30\uc5d0\uc11c \uc694\uc18c\ub97c \ud130\uce58\ub85c \uc2a4\uc640\uc774\ud504\ud560 \uc218 \uc788\ub3c4\ub85d \ud558\ub294 Modifier\ub85c \ub9cc\ub4e4\ub824\uace0 \ud55c\ub2e4. \uc694\uc18c\uac00 \ud654\uba74 \uac00\uc7a5\uc790\ub9ac\ub85c \ud50c\ub9c1\ub420 \ub54c, \uc694\uc18c\ub97c \uc81c\uac70\ud560 \uc218 \uc788\ub3c4\ub85d onDismissed \ucf5c\ubc31\uc744 \ud638\ucd9c\ud55c\ub2e4.<\/p>\n\n\n\n<p>Animateable\uc740 \uc9c0\uae08\uae4c\uc9c0 \ubcf8 \uac83\uc911 \uac00\uc7a5 \ub85c\uc6b0 \ub808\ubca8 API\ub2e4. \uc81c\uc2a4\ucc98 \uc2dc\ub098\ub9ac\uc624\uc5d0\uc11c \uc720\uc6a9\ud55c \uba87 \uac00\uc9c0 \uae30\ub2a5\uc774 \uc788\uc73c\ubbc0\ub85c, Animateable\uc758 \uc778\uc2a4\ud134\uc2a4\ub97c \ub9cc\ub4e4\uace0, \uc2a4\uc640\uc774\ud504\ud560 \uc218 \uc788\ub294 \uc694\uc18c\uc758 \uc218\ud3c9 \uc624\ud504\uc14b\uc744 \ub098\ud0c0\ub0b4\ub294 \ub370 \uc0ac\uc6a9\ud558\uaca0\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>val offsetX = remember { Animatable(0f) } \/\/ \uc774 \ub77c\uc778\uc744 \ucd94\uac00\ud55c\ub2e4.\npointerInput {\n\u00a0 \u00a0 \/\/ \ud50c\ub9c1 \uc560\ub2c8\uba54\uc774\uc158\uc774 \uba48\ucd94\ub294 \ud3ec\uc9c0\uc158\uc744 \uacc4\uc0b0 \ud558\uae30 \uc704\ud574 \uc0ac\uc6a9\ub428\n\u00a0 \u00a0 val decay = splineBasedDecay&lt;Float>(this)\n\u00a0 \u00a0 \/\/ \ucf54\ub8e8\ud2f4 \uc2a4\ucf54\ud504\ub85c \uac10\uc2f8 \ud130\uce58 \uc774\ubca4\ud2b8 \ubc0f \uc560\ub2c8\uba54\uc774\uc158\uc744 \uc704\ud55c suspend function\uc744 \uc0ac\uc6a9\ud55c\ub2e4.\n\u00a0 \u00a0 coroutineScope {\n\u00a0 \u00a0 \u00a0 \u00a0 while (true) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ ...<\/code><\/pre>\n\n\n\n<p>TODO 6-2\ub294 \ud130\uce58\ub2e4\uc6b4 \uc774\ubca4\ud2b8\ub97c \ubc1b\uc740 \uacf3\uc774\ub2e4. \uc560\ub2c8\uba54\uc774\uc158\uc774 \ud604\uc7ac \uc2e4\ud589 \uc911\uc774\uba74 \uac00\ub85c\ucc44\uc57c \ud55c\ub2e4. \uc774\uac83\uc740 Animateable\uc5d0\uc11c stop\uc744 \ud638\ucd9c\ud558\uc5ec \uc218\ud589\ud560 \uc218 \uc788\ub2e4. \uc560\ub2c8\uba54\uc774\uc158\uc774 \uc2e4\ud589\ub418\uace0 \uc788\uc9c0 \uc54a\uc73c\uba74 \ud638\ucd9c\uc774 \ubb34\uc2dc\ub41c\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \ud130\uce58\ub2e4\uc6b4 \uc774\ubca4\ud2b8\ub97c \uae30\ub2e4\ub9b0\ub2e4.\nval pointerId = awaitPointerEventScope { awaitFirstDown().id }\noffsetX.stop() \/\/ \uc774 \ub77c\uc778\uc744 \ucd94\uac00\ud558\uc790\n\/\/ \ub4dc\ub798\uadf8 \uc774\ubca4\ud2b8\ub97c \uc900\ube44\ud558\uace0 \ud50c\ub9c1\uc2dc\uc758 \uc18d\ub3c4\ub97c \uae30\ub85d\ud55c\ub2e4. \nval velocityTracker = VelocityTracker()\n\/\/ \ub4dc\ub798\uadf8 \uc774\ubca4\ud2b8\ub97c \uae30\ub2e4\ub9b0\ub2e4.\nawaitPointerEventScope {<\/code><\/pre>\n\n\n\n<p>TODO 6-3\uc5d0\uc11c\ub294 \uc9c0\uc18d\uc801\uc73c\ub85c \ub4dc\ub798\uadf8 \uc774\ubca4\ud2b8\ub97c \uc218\uc2e0\ud558\uace0 \uc788\ub2e4. \ud130\uce58 \uc774\ubca4\ud2b8\uc758 \uc704\uce58\ub97c \u200b\u200b\uc560\ub2c8\uba54\uc774\uc158 \uac12\uacfc \ub3d9\uae30\ud654\ud574\uc57c \ud558\ubbc0\ub85c, \uc774\ub97c \uc704\ud574 Animateable\uc5d0\uc11c snapTo\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>horizontalDrag(pointerId) { change ->\n\u00a0 \u00a0 \/\/ \uc5ec\uae30\uc5d0 4\uc904\uc744 \ucd94\uac00\ud55c\ub2e4.\n\u00a0 \u00a0 val horizontalDragOffset = offsetX.value + change.positionChange().x\n\u00a0 \u00a0 launch {\n\u00a0 \u00a0 \u00a0 \u00a0 offsetX.snapTo(horizontalDragOffset)\n\u00a0 \u00a0 }\n\u00a0 \u00a0 \/\/ \ub4dc\ub798\uadf8\uc758 \uc18d\ub3c4\ub97c \uae30\ub85d\ud55c\ub2e4.\n\u00a0 \u00a0 velocityTracker.addPosition(change.uptimeMillis, change.position)\n\u00a0 \u00a0 \/\/ \uc81c\uc2a4\uccd0 \uc774\ubca4\ud2b8\ub97c \uc18c\ube44\ud558\uace0, \uc678\ubd80\ub85c \uc804\ub2ec\uc2dc\ud0a4\uc9c0 \uc54a\ub294\ub2e4.\n\u00a0 \u00a0 change.consumePositionChange()\n}<\/code><\/pre>\n\n\n\n<p>TODO 6-4\ub294 \ud574\ub2f9 \uc694\uc18c\uac00 \ubc29\uae08 \ub9b4\ub9ac\uc988 \ub418\uace0 \ud50c\ub9c1\ub418\uc5c8\ub358 \uacf3\uc774\ub2e4. \uc694\uc18c\ub97c \uc6d0\ub798 \uc704\uce58\ub85c \ub2e4\uc2dc \ubc00\uc5b4\uc57c \ud558\ub294\uc9c0, \uc544\ub2c8\uba74 \ubc00\uc5b4\uc11c \ucf5c\ubc31\uc744 \ud638\ucd9c\ud574\uc57c \ud558\ub294\uc9c0\ub97c \uacb0\uc815\ud558\uae30 \uc704\ud574 \ud50c\ub9c1\uc774 \uba48\ucd94\ub294 \ucd5c\uc885 \uc704\uce58\ub97c \uacc4\uc0b0\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \ub4dc\ub798\uadf8\uac00 \ub05d\ub0ac\ub2e4. \ud50c\ub9c1\uc758 \uc18d\ub3c4\ub97c \uacc4\uc0b0\ud558\uc790.\nval velocity = velocityTracker.calculateVelocity().x\n\/\/ \uc774 \ub77c\uc778\uc744 \ucd94\uac00\ud55c\ub2e4.\nval targetOffsetX = decay.calculateTargetValue(offsetX.value, velocity) <\/code><\/pre>\n\n\n\n<p>TODO 6-5\uc5d0\uc11c\ub294 \uc560\ub2c8\uba54\uc774\uc158\uc744 \uc2dc\uc791\ud558\ub824\uace0 \ud55c\ub2e4. \uadf8\ub7ec\ub098 \uadf8 \uc804\uc5d0 Animateable\uc5d0 \uc0c1\ud55c \ubc0f \ud558\ud55c \uac12 \uacbd\uacc4(bound)\ub97c \uc124\uc815\ud558\uc5ec, \uacbd\uacc4\uc5d0 \ub3c4\ub2ec\ud558\ub294 \uc989\uc2dc \uc911\uc9c0\ub418\ub3c4\ub85d \ud55c\ub2e4. pointerInput Modifier\ub97c \uc0ac\uc6a9\ud558\uba74 size \uc18d\uc131\uc73c\ub85c \uc694\uc18c\uc758 \ud06c\uae30\uc5d0 \uc561\uc138\uc2a4\ud560 \uc218 \uc788\uc73c\ubbc0\ub85c \uc774\ub97c \uc0ac\uc6a9\ud558\uc5ec \uacbd\uacc4\ub97c \uc5bb\ub294\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>offsetX.updateBounds(<br>&nbsp; &nbsp; lowerBound = -size.width.toFloat(),<br>&nbsp; &nbsp; upperBound = size.width.toFloat()<br>)<\/code><\/pre>\n\n\n\n<p>TODO 6-6\uc740 \ub4dc\ub514\uc5b4 \uc560\ub2c8\uba54\uc774\uc158\uc744 \uc2dc\uc791\ud560 \uc218 \uc788\ub294 \uacf3\uc774\ub2e4. \uba3c\uc800 \uc55e\uc11c \uacc4\uc0b0\ud55c \ud50c\ub9c1\uc758 \uba48\ucd9c \uc704\uce58\uc640 \uc694\uc18c\uc758 \ud06c\uae30\ub97c \ube44\uad50\ud55c\ub2e4. \uace0\uc815\ub418\ub294 \uc704\uce58\uac00 \uc0ac\uc774\uc988 \uc774\ud558\uc774\uba74 \ud50c\ub9c1\uc758 \uc18d\ub3c4\uac00 \ucda9\ubd84\ud558\uc9c0 \uc54a\ub2e4\ub294 \uac83\uc744 \uc758\ubbf8\ud55c\ub2e4. animateTo\ub97c \uc0ac\uc6a9\ud558\uc5ec \uac12\uc744 0f\ub85c \ub418\ub3cc\ub9b4 \uc218 \uc788\ub2e4. \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74, \uc6b0\ub9ac\ub294 \ud50c\ub9c1 \uc560\ub2c8\uba54\uc774\uc158\uc744 \uc2dc\uc791\ud558\uae30 \uc704\ud574 animateDecay\ub97c \uc0ac\uc6a9\ud55c\ub2e4. \uc560\ub2c8\uba54\uc774\uc158\uc774 \uc644\ub8cc\ub418\uba74(\ub300\ubd80\ubd84 \uc774\uc804\uc5d0 \uc124\uc815\ud55c \uacbd\uacc4\uc5d0 \ub530\ub77c) \ucf5c\ubc31\uc744 \ud638\ucd9c\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>launch {\n\u00a0 \u00a0 if (targetOffsetX.absoluteValue &lt;= size.width) {\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \uc18d\ub3c4\uac00 \ucda9\ubd84\ud558\uc9c0 \uc54a\uc73c\uba74 \uc2ac\ub77c\uc774\ub4dc\ub97c \ub3cc\ub824\ub193\ub294\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 offsetX.animateTo(targetValue = 0f, initialVelocity = velocity)\n\u00a0 \u00a0 } else {\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \uc694\uc18c\ub97c \uac00\uc7a5\uc790\ub9ac\ub85c \ubc00\uc5b4\ub0b4\uae30\uc5d0 \ucda9\ubd84\ud55c \uc18d\ub3c4\n\u00a0 \u00a0 \u00a0 \u00a0 offsetX.animateDecay(velocity, decay)\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \uc694\uc18c\ub97c \uc2a4\uc640\uc774\ud504\ud558\uc5ec \uc81c\uac70\ud588\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 onDismissed()\n\u00a0 \u00a0 }\n}<\/code><\/pre>\n\n\n\n<p>\ub9c8\uc9c0\ub9c9\uc73c\ub85c TODO 6-7\uc744 \ucc38\uc870\ud558\uc790. \ubaa8\ub4e0 \uc560\ub2c8\uba54\uc774\uc158\uacfc \uc81c\uc2a4\ucc98\uac00 \uc124\uc815\ub418\uc5c8\uc73c\ubbc0\ub85c, \uc694\uc18c\uc5d0 \uc624\ud504\uc14b\uc744 \uc801\uc6a9\ud558\ub294 \uac83\uc744 \uc78a\uc9c0 \ub9d0\uc790.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.offset { IntOffset(offsetX.value.roundToInt(), 0) }<\/code><\/pre>\n\n\n\n<p>\uc774 \uc139\uc158\uc758 \uacb0\uacfc\ub85c, \uacb0\uad6d \ub2e4\uc74c\uacfc \uac19\uc740 \ucf54\ub4dc\ub97c \ub098\ud0c0\ub0b8\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private fun Modifier.swipeToDismiss(\n\u00a0 \u00a0 onDismissed: () -> Unit\n): Modifier = composed {\n\u00a0 \u00a0 \/\/ \uc774 `Animatable` \uc694\uc18c\uc5d0 \ub300\ud55c \uc218\ud3c9 \uc624\ud504\uc14b\uc744 \uc800\uc7a5\ud55c\ub2e4.\n\u00a0 \u00a0 val offsetX = remember { Animatable(0f) }\n\u00a0 \u00a0 pointerInput(Unit) {\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ud50c\ub9c1 \uc560\ub2c8\uba54\uc774\uc158\uc5d0\uc11c \uc815\ucc29\ub420 \ud3ec\uc9c0\uc158\uc744 \uacc4\uc0b0\ud558\ub294\ub370 \uc0ac\uc6a9\ub41c\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 val decay = splineBasedDecay&lt;Float>(this)\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ucf54\ub8e8\ud2f4 \uc2a4\ucf54\ud504\ub85c \uac10\uc2f8 \ud130\uce58\uc774\ubca4\ud2b8 \ubc0f \uc560\ub2c8\uba54\uc774\uc158\uc5d0 \ub300\ud55c suspend \ud568\uc218\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc788\ub3c4\ub85d \ud55c\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 coroutineScope {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 while (true) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ud130\uce58 \ub2e4\uc6b4 \uc774\ubca4\ud2b8\ub97c \uae30\ub2e4\ub9b0\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 val pointerId = awaitPointerEventScope { awaitFirstDown().id }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \uc9c4\ud589\uc911\uc778 \uc774\ubca4\ud2b8\ub97c \uba48\ucd98\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 offsetX.stop()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ub4dc\ub798\uadf8 \uc774\ubca4\ud2b8\ub97c \uc704\ud574 \uc900\ube44\ud558\uace0 \ud50c\ub9c1 \uc18d\ub3c4\ub97c \uae30\ub85d\ud55c\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 val velocityTracker = VelocityTracker()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ub4dc\ub798\uadf8 \uc774\ubca4\ud2b8\ub97c \uae30\ub2e4\ub9b0\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 awaitPointerEventScope {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 horizontalDrag(pointerId) { change ->\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \uc624\ud504\uc14b \uc774\ud6c4 \ud3ec\uc9c0\uc158\uc744 \uae30\ub85d\ud55c\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 val horizontalDragOffset = offsetX.value + change.positionChange().x\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 launch {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \uc694\uc18c\uac00 \ub4dc\ub798\uadf8 \ub418\ub294 \ub3d9\uc548 `Animatable` \uac12\uc744 \ub36e\uc5b4\uc4f4\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 offsetX.snapTo(horizontalDragOffset)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ub4dc\ub798\uadf8 \uc18d\ub3c4\ub97c \uae30\ub85d\ud55c\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 velocityTracker.addPosition(change.uptimeMillis, change.position)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \uc81c\uc2a4\ucc98 \uc774\ubca4\ud2b8\ub97c \uc18c\ube44\ud558\uace0 \uc678\ubd80\ub85c \uc804\ub2ec\ud558\uc9c0 \uc54a\ub294\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 change.consumePositionChange()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ub4dc\ub798\uadf8\uac00 \ub05d\ub0ac\ub2e4. \ud50c\ub9c1 \uc18d\ub3c4\ub97c \uacc4\uc0b0\ud55c\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 val velocity = velocityTracker.calculateVelocity().x\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ud50c\ub9c1 \uc560\ub2c8\uba54\uc774\uc158 \uc774\ud6c4\uc5d0 \ud574\ub2f9 \uc694\uc18c\uac00 \uad81\uadf9\uc801\uc73c\ub85c \uc815\ucc29\ub420 \uc704\uce58\ub97c \uacc4\uc0b0\ud55c\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 val targetOffsetX = decay.calculateTargetValue(offsetX.value, velocity)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \uc560\ub2c8\uba54\uc774\uc158\uc740 \uacbd\uacc4\uc5d0 \ub3c4\ub2ec\ud558\uc790\ub9c8\uc790 \ub05d\ub098\uc57c \ud55c\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 offsetX.updateBounds(\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 lowerBound = -size.width.toFloat(),\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 upperBound = size.width.toFloat()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 )\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 launch {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if (targetOffsetX.absoluteValue &lt;= size.width) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \uc18d\ub3c4\uac00 \ucda9\ubd84\ud558\uc9c0 \uc54a\ub2e4; \uae30\ubcf8 \uc704\uce58\ub85c \ub2e4\uc2dc \uc2ac\ub77c\uc774\ub4dc\ud574 \ub3cc\ub824\ub193\ub294\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 offsetX.animateTo(targetValue = 0f, initialVelocity = velocity)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 } else {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ud574\ub2f9 \uc694\uc18c\ub97c \uac00\uc7a5\uc790\ub9ac\ub85c \ubc00\uc5b4\ub0b4\uae30\uc5d0 \uc18d\ub3c4\uac00 \ucda9\ubd84\ud558\ub2e4\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 offsetX.animateDecay(velocity, decay)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ud574\ub2f9 \uc694\uc18c\uac00 \uc2a4\uc640\uc774\ud504 \ub418\uc5c8\ub2e4.\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 onDismissed()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ \ud574\ub2f9\uc694\uc18c\uc5d0 \uc218\ud3c9 \uc624\ud504\uc14b\uc744 \uc801\uc6a9\ud558\uc790.\n\u00a0 \u00a0 \u00a0 \u00a0 .offset { IntOffset(offsetX.value.roundToInt(), 0) }\n}<\/code><\/pre>\n\n\n\n<p>\uc571\uc744 \uc2e4\ud589\ud558\uace0 \uc791\uc5c5 \uc544\uc774\ud15c \uc911 \ud558\ub098\ub97c \uc0b4\uc9dd \ubc00\uc5b4\ubcf4\uc790 \uc694\uc18c\uac00 \ud50c\ub9c1 \uc18d\ub3c4\uc5d0 \ub530\ub77c, \uae30\ubcf8 \uc704\uce58\ub85c \ub2e4\uc2dc \ubbf8\ub044\ub7ec\uc9c0\uace0, \uba40\uc5b4\uc9c0\uace0, \uc81c\uac70\ub418\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4. \uc560\ub2c8\uba54\uc774\uc158\uc774 \uc9c4\ud589\ub418\ub294 \ub3d9\uc548 \ud574\ub2f9 \uc694\uc18c\ub97c \ubd99\uc7a1\uc744 \uc218\ub3c4 \uc788\ub2e4.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/developer.android.com\/codelabs\/jetpack-compose-animation\/img\/7cdefce823f6b9bd.png?hl=ko\" alt=\"7cdefce823f6b9bd.png\"\/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\uc774 \ub9c8\uc9c0\ub9c9 \uc139\uc158\uc5d0\uc11c\ub294 \ud130\uce58 \uc785\ub825\uc744 \uae30\ubc18\uc73c\ub85c \uc560\ub2c8\uba54\uc774\uc158\uc744 \uc2e4\ud589\ud558\ub294 \ubc29\ubc95\uc5d0 \ub300\ud574 \uc54c\uc544\ubcf4\uc790. \uc774 \uc2dc\ub098\ub9ac\uc624\uc5d0\uc11c \uace0\ub824\ud574\uc57c \ud560 \uba87 \uac00\uc9c0 \uace0\uc720\ud55c \uc0ac\ud56d\uc774 \uc788\ub2e4. \uccab\uc9f8, \uc9c4\ud589 \uc911\uc778 \uc560\ub2c8\uba54\uc774\uc158\uc774 \ud130\uce58 \uc774\ubca4\ud2b8\uc5d0 \uc758\ud574 \uac00\ub85c\ucc4c \uc218 \uc788\ub2e4. \ub458\uc9f8, \uc560\ub2c8\uba54\uc774\uc158 \uac12\uc774 \uc720\uc77c\ud55c \uc815\ubcf4 \uc18c\uc2a4\uac00 \uc544\ub2d0 \uc218\ub3c4 \uc788\ub2e4. \uc989, \uc560\ub2c8\uba54\uc774\uc158 \uac12\uc744 \ud130\uce58 \uc774\ubca4\ud2b8\uc5d0\uc11c \uc624\ub294 \uac12\uacfc \ub3d9\uae30\ud654\ud574\uc57c \ud560 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[38],"tags":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/posts\/45738"}],"collection":[{"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/charlezz.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=45738"}],"version-history":[{"count":1,"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/posts\/45738\/revisions"}],"predecessor-version":[{"id":45739,"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/posts\/45738\/revisions\/45739"}],"wp:attachment":[{"href":"https:\/\/charlezz.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=45738"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/charlezz.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=45738"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/charlezz.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=45738"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}