#1 ๊ฐ์
#1-1 ๊ณต์ ๋ฌธ์
๋๋๊ทธ, ์ค์์ดํ, ํ๋ง | Jetpack Compose | Android Developers
์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. ๋๋๊ทธ, ์ค์์ดํ, ํ๋ง ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. draggable ์์ ์๋ ๋์์ ํ ๋ฐฉ
developer.android.com
์ ๊ณต์ ๋ฌธ์๋ฅผ ๋์ ์ธ์ด๋ก ์ ๋ฆฌํ๋ค.
#1-2 AnchoredDraggable
Swipeable์์ AnchoredDraggable๋ก ์ด์ | Jetpack Compose | Android Developers
์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. Swipeable์์ AnchoredDraggable๋ก ์ด์ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. ๊ฒฝ๊ณ : ์ด ํ์ด์ง์ ์ฌ
developer.android.com
Swipeable์ด AnchoredDraggable๋ก ์ ๊ทธ๋ ์ด๋๋์๋ค๊ณ ํ๋ค. ์ ๋งํฌ๋ ํด๋น ์ ๋ฐ์ดํธ๋ฅผ ์ ํ๋ ํ์ด์ง๋ค.
#1-3 ์ ํ๋ธ ์์
AnchoredDraggable์ ๋ํ ๊ฐ๋ก ์ ๋ด์ ๊ณต์ ์์์ด๋ค. ์์ธ์ง๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง, ์์ ์ธ๋ค์ผ์ ์๋๋ก์ด๋ ์บ๋ฆญํฐ๊ฐ ํด์ ์ด ์ธ ๋ฒํ ์๋๋ฅผ ์ฐ๊ณ ์๋ค.
#2 ๋๋๊ทธ (drag)
#2-1 ๊ฐ์
Modifier.draggable()์ ์ปดํฌ๋ํธ์ ๋๋๊ทธ๋ฅผ '๊ฐ๋ฅํ๊ฒ' ํ๋ค. Modifier.draggable() ๋ง์ผ๋ก ๋๋๊ทธ๊ฐ '๋๋' ๊ฒ์ ์๋๋ค. Modifier.scrollable()๊ณผ ๊ฐ์ ๋งฅ๋ฝ์ด๋ค. Modifier.scrollable()์ ๋ํด ๋ค๋ฃฌ ์๋ ๋งํฌ์ ๊ฒ์๊ธ์ ์ฝ์ผ๋ฉด ์ดํด๊ฐ ์ฌ์ธ ๊ฒ์ด๋ค.
[Android] Pointer input - Scroll
#1 ๊ฐ์ ์คํฌ๋กค | Jetpack Compose | Android Developers์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. ์คํฌ๋กค ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ
kenel.tistory.com
์ ๊ฒ์๊ธ์์, ์คํฌ๋กค์ '๊ฐ๋ฅํ๊ฒ' ํ๋ ๊ฒ์ Modifier.scrollable()์ด์๋ค. ๊ทธ๋ฆฌ๊ณ ์คํฌ๋กค์ด '๋๊ฒ' ํ๋ ๊ฒ์ Modifier.verticalScroll() ๋๋ Modifier.horizontalScroll()์ด์๋ค. ์ด์ ๋น์ทํ๊ฒ ๋๋๊ทธ๋ฅผ '๊ฐ๋ฅํ๊ฒ' ํ๋ ๊ฒ์ Modifier.draggable()์ด๋ค. ๊ทธ๋ฆฌ๊ณ ๋๋๊ทธ๊ฐ '๋๊ฒ' ํ๋ ๊ฒ์ detectDragGestures()๋ค.
#2-2 Modifier.draggable()๊ฐ ์ฌ์ฉ๋ ์ฝ๋ ์์
@Composable
private fun DraggableText() {
var offsetX by remember { mutableStateOf(0f) }
Text(
modifier = Modifier
.offset { IntOffset(offsetX.roundToInt(), 0) }
.draggable(
orientation = Orientation.Horizontal,
state = rememberDraggableState { delta ->
offsetX += delta
}
),
text = "Drag me!"
)
}
#2-3 detectDragGestures()๊ฐ ์ฌ์ฉ๋ ์ฝ๋ ์์
@Composable
private fun DraggableTextLowLevel() {
Box(modifier = Modifier.fillMaxSize()) {
var offsetX by remember { mutableStateOf(0f) }
var offsetY by remember { mutableStateOf(0f) }
Box(
Modifier
.offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
.background(Color.Blue)
.size(50.dp)
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consume()
offsetX += dragAmount.x
offsetY += dragAmount.y
}
}
)
}
}
#3 ํ๋ง (fling)
ํ๋ง(fling)์ด๋, ๋๋๊ทธ ๋์ค ์์ ๋ผ๋ ๊ฒ์ ์๋ฏธํ๋ค. ์ค๋งํธํฐ์์ ์น ํ์ด์ง๋ฅผ ์คํฌ๋กคํ ๋๋ฅผ ๋ ์ฌ๋ ค ๋ณด๋ผ. ์๊ฐ๋ฝ์ผ๋ก ํ๋ฉด์ ๋๋๊ทธํ๋ค๊ฐ ์์ ๊ฐ์๊ธฐ ํ ๋ผ๋ฉด, ๋ง์น ์คํฌ๋กค์ ๊ด์ฑ์ด ์๋ ๊ฒ์ฒ๋ผ ์ฌ์ ํ ์คํฌ๋กค๋์ง ์๋๊ฐ? ๊ทธ๊ฑธ์ ํ๋ง์ด๋ผ๊ณ ํ๋ค. ์ญ๋ฐฉํฅ์ผ๋ก ์๊ฐํด๋ณด๋ฉด, ํ๋ง์ ๋ฐ๋์ ๋๋๊ทธ๊ฐ ์ ํ๋์ด์ผ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ผ๋ ๊ฒ๋ ์ ์ ์๋ค.
#4 ์ค์์ดํ (swipe)

์ค์์ดํ(swipe)๋, ๋๋๊ทธ๋ ํ๋ง ์ข ๋ฃ ์ ์ปดํฌ๋ํธ๊ฐ (ํ๋ก๊ทธ๋๋จธ์ ์ํด ์ ํด์ง) '์ต์ปค ํฌ์ธํธ'๋ก ์ด๋ํ๋ ์ด๋ฒคํธ๋ค. ์ญ๋ฐฉํฅ์ผ๋ก ์๊ฐํด๋ณด๋ฉด, ์ค์์ดํ๋ ๋ฐ๋์ ๋๋๊ทธ ๋๋ ํ๋ง์ด ์ ํ๋์ด์ผ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ผ๋ ๊ฒ๋ ์ ์ ์๋ค. ์ค์์ดํ ๋์์ ์ํด์ Modifier.swipeable()์ด ํ์ํ๋ค. ๊ทธ๋ฌ๋ #1-2์์ ๋งํ๋ฏ, Swipeable๋ deprecated๋ ์์ ์ด๋ค. ๋ฐ๋ผ์ ๋ณธ ๊ฒ์๊ธ์์ Modifier.swipeable() ๋์ Modifier.anchoredDraggable()์ ์ฌ์ฉํ๋ค.
#5 AnchoredDraggable
#5-1 ๊ฐ์
๊ณต์ ๋ฌธ์์ ์๋ ๋ด์ฉ์ ์ ์ฝ๊ณ ์ํํ๋ คํ๋ค. ํ์ง๋ง ๋ฌ์์ค๋ง ์ดํด๋์๊ณ ๋ด๋ถ ๊ธฐ์ ๋ฅผ ์ ํํ ์ดํดํ ์ ์์๋ค. ์ด๋ฐ ๊ฒํฅ๊ธฐ์ ์ดํด๋ก๋, ์ค์ ๊ตฌํ์ ํ ์ ์๋ค. ๋ฐ๋ผ์ ๋ฏธ๋ ํ๋ก์ ํธ๋ฅผ ํตํด ๊ณต์ ๋ฌธ์์ ์ฝ๋๋ฅผ ๋ฐ๋ผํด๋ณด๊ฒ ๋ค. ์ฐ์ AnchoredDraggableExample์ด๋ผ๋ ์ด๋ฆ์ Jetpack Compose ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์๋ค.
#5-2 ๊ธฐ๋ณธ ๊ตฌ์กฐ
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun AnchoredDraggableBox() {
val state = remember {
AnchoredDraggableState(
// TODO
)
}
Box(
modifier = Modifier
.offset { /* TODO */ }
.width(200.dp)
.height(200.dp)
.background(Color.LightGray)
.anchoredDraggable(
state = state,
orientation = /* TODO */
)
) {
Text("Swipe me")
}
}
AnchoredDrag๋ฅผ ์ ์ฉํ ์ปดํฌ๋ํธ์ Modifier.anchoredDraggable() ๋ฐ Modifier.offset()์ ๋ถ์ธ๋ค. ๊ทธ๋ฆฌ๊ณ AnchoredDrag์ ํต์ฌ์ธ AnchoredDraggableState๋ฅผ ์ ์ธํ์ฌ anchoredDraggable() ๋ฐ offset() ์์ ๋ฃ์ด์ฃผ๋ ๊ฒ์ผ๋ก AnchoredDrag๊ฐ ๋์ํ๊ฒ ๋๋ค.
#5-3 AnchoredDraggableState
@ExperimentalFoundationApi public constructor AnchoredDraggableState<T>(
initialValue: T,
anchors: DraggableAnchors<T>,
positionalThreshold: (totalDistance: Float) -> Float,
velocityThreshold: () -> Float,
animationSpec: AnimationSpec<Float>,
confirmValueChange: (newValue: T) -> Boolean = { true }
)
AnchoredDraggableState๋ AnchoredDrag๋ฅผ ์ํ ๋ชจ๋ ์ ๋ณด๊ฐ ๋ค์ด์๋ค. ๊ฐ ์ธ์์ ๋ํ ์ค๋ช ์ ์๋์ ๊ฐ๋ค.
initialValue: T
์๋ฅผ ๋ค์ด, #5-2 ์ฝ๋ ์ Box()์ ์ด๊ธฐ ์์น๋ฅผ ์๋ฏธํ๋ค.
anchors: DraggableAnchors<T>
์ฌ๋ฌ '์ต์ปค ํฌ์ธํธ'์ ๋ชฉ๋ก์ด๋ค.
positionalThreshold: (totalDistance: Float) -> Float
๋ค๋ฅธ '์ต์ปค ํฌ์ธํธ'๋ก ์ด๋๋๊ธฐ ์ํ ์ต์ ๊ฑฐ๋ฆฌ. ์ฆ ์ด ๊ฐ์ด ์๋ค๋ฉด ์ด์ง๋ง ์ค์์ดํํด๋ ๋ค๋ฅธ ์ต์ปค ํฌ์ธํธ๋ก ๋ ์๊ฐ๋ฒ๋ฆด ๊ฒ์ด๋ค.
velocityThreshold: () -> Float
positionalThreshold์ ๊ฐ์ ๋์ง ์์์ด๋, ๋๋๊ทธ ๋์์ ์๋(velocity)๊ฐ ๋๋ค๋ฉด ๋ค๋ฅธ '์ต์ปค ํฌ์ธํธ'๋ก ์ด๋ํ๋๊ฒ ์์ฐ์ค๋ฝ๋ค. ์ด ์ธ์๋ ๊ทธ ์๋ ๊ฐ์ ์ ์ํ๋ค.
animationSpec: AnimationSpec<Float>
์ด๋ป๊ฒ(how) ๋ค๋ฅธ ์ต์ปค ํฌ์ธํธ๋ก ์ด๋ํ๋ ์ง ์ ์ํ๋ค. ์ ๋๋ฉ์ด์ ๋์์ ์ ์ํ๋ค๋ ๋ง์ด๋ค.
confirmValueChange: (newValue: T) -> Boolean
confirmValueChange๋ฅผ ๋จ์ ํด์ํ๋ฉด '์ต์ปค ํฌ์ธํธ'๋ก ์ด๋ํจ์ ํ์ฉํ๋ค๋ ๋ง์ด๋ค. ๊ธฐ๋ณธ๊ฐ์ true๋ก ๋์ด์๊ธฐ์ ํน์ ์ต์ปค ํฌ์ธํธ๋ก ์ด๋ํ๋ ๊ฒ ๋งํ ์ผ์ด ์์ง๋ง, ํ๋ก๊ทธ๋๋จธ๊ฐ confirmValueChange๋ฅผ ํตํด์ ๋งค์ฐ ์ธ์ธํ ํต์ ๋ฅผ ๊ฐํ ์๋ ์๋ค. ๊ฐ๋ น ์ด๋ค ๋ณ์๊ฐ ์ด๋ค ๊ฐ์ธ ๊ฒฝ์ฐ์๋ง ์ด๋์ ํ์ฉํ๋ ์์ด๋ค.
#5-4 ์์ ์ฝ๋
enum class DragValue { Start, Center, End }
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun AnchoredDraggableBox() {
val density = LocalDensity.current
val anchors = with(density) {
DraggableAnchors {
DragValue.Start at -250.dp.toPx()
DragValue.Center at 0f
DragValue.End at 250.dp.toPx()
}
}
val state = remember {
AnchoredDraggableState(
initialValue = DragValue.Center,
anchors = anchors,
positionalThreshold = { distance -> distance * 0.5f }, // (1)
velocityThreshold = { with(density) { 125.dp.toPx() } }, // (2)
animationSpec = spring(), // (3)
)
}
Box(
Modifier
.offset { IntOffset(x = 0, y = state.requireOffset().roundToInt()) } // (4)
.width(200.dp)
.height(200.dp)
.background(Color.LightGray)
.anchoredDraggable(
state = state,
orientation = Orientation.Vertical
)
) {
Text("Swipe me")
}
}
(1) positionalThreshold = { distance -> distance * 0.5f }
distance๋ ๋ '์ต์ปค ํฌ์ธํธ' ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ์๋ฏธํ๋ค. ๊ทธ ๊ฑฐ๋ฆฌ์ ์ ๋ฐ(0.5f) ์ด์ ๋๋๊ทธํ๋ค๋ฉด ์ค์์ดํ๊ฐ ์คํ๋๋ค.
(2) velocityThreshold = { with(density) { 125.dp.toPx() } }
์ฌ์ฉ์๊ฐ ์์ ๋ ๋์ ์๋๊ฐ (125.dp / 1์ด)์ด์์ด๋ฉด, ์ค์์ดํ๊ฐ ์คํ๋จ์ ์๋ฏธํ๋ค. ์๋๋ Compose ๋ด๋ถ์์๋ (px / ์ด) ๋จ์์ด๊ธฐ์, ํฝ์ ๋ก ๋ณํํ๋ค. ๊ทธ๋ผ ๊ทธ๋ฅ ์ฒ์๋ถํฐ (px / ์ด) ๋จ์๋ก ๋ฃ์ด์ฃผ๋ฉด ๋์ง์์๊น? ๊ฐ๋ฅ์ ํ๋ค. ๊ทธ๋ฌ๋ ์์ฐ์ค๋ฝ์ง ์๋ค. (px / ์ด) ๋จ์๋ฅผ ๋ฃ์ผ๋ ค๋ ์๋๋ ๋ง์น, ๊ฑด์ถ๊ฐ๋ค์ด ์ํํธ์ ๋์ด๋ฅผ "์ด ๋ช m์ธ๊ฐ?"๊ฐ ์๋ "์ด ๋ช ์ธต์ธ๊ฐ?"๋ก ํ์ ํ๋ ค๋ ์๋์ ๊ฐ๋ค. ๋ฐ๋ผ์ ์ฝ๋์์๋ ์ธ๊ฐ(ํ๋ก๊ทธ๋๋จธ) ์ ์ฅ์์ ์ ํํ ๋จ์์ธ dp๋ก ์ ๋ ๊ฒ์ด๋ค.
(3) animationSpec = spring()
spring์ ์๋๋ก์ด๋์ ๊ธฐ๋ณธ ์ ๋๋ฉ์ด์ ์ด๋ค. spring์ ์ปค์คํ ์ ํ ์๋ ์๋ค.
(4) y = state.requireOffset().roundToInt()
requireOffset()์ Modifier.anchoredDraggable()๊ฐ ๋ถ์ ์ปดํฌ์ ๋ธ ๊ฐ์ฒด์ offset๋ฅผ ๋ฐํํ๋ค.
#5-5 ๋์์ 1
์ ์๋ํ์ง๋ง ์ฒซ ์ต์ปค ํฌ์ธํธ์ ๋ ์ต์ปค ํฌ์ธํธ์์ ๋ ์ค์์ดํ๋ ์ ์๋ ๋ฐฉํฅ์ผ๋ก ๋๋๊ทธํ์ ๋, Box()๊ฐ ์์ฐ๊ฑฐ๋ฆฌ๋ ๊ฒ ๋ง์์ ๋ค์ง ์์๋ค.
#5-6 ๊น๋ํ๊ฒ ๋ค๋ฌ๊ธฐ
Box(
Modifier
.offset {
IntOffset(
x = 0,
y = state.requireOffset()
.coerceIn(anchors.minAnchor(), anchors.maxAnchor())
.roundToInt()
)
}
...
) {
Text("Swipe me")
}
ํ์ง๋ง offset๋ฅผ ์ด๋ ๊ฒ ๋ณ๊ฒฝํ๋ฉด,
#5-7 ๋์์ 2
์์ฐ๊ฑฐ๋ฆฌ๋ ํ์์ ์ ๊ฑฐํ ์ ์๋ค.
#5-8 ์ฝ๋ ์ ๋ฐ์ดํธ
Compose ๊ธฐ์ด | Jetpack | Android Developers
developer.android.com
Jetpack compose 1.7.0-alpha01 ๋ฒ์ ๋ถํฐ, AnchoredDraggableState์ ์ธ์ animationSpec์ ์ด๋ฆ์ด snapAnimationSpec์ผ๋ก ๋ฐ๋์๊ณ decayAnimationSpec์ด๋ผ๋ ์ธ์๊ฐ ์ถ๊ฐ๋์๋ค.
๋, 1.8.0-alpha06 ๋ฒ์ ๋ถํฐ๋ confirmValueChange ์ธ์๊ฐ ์ญ์ ๋์๋ค. confirmValueChange๋ฅผ ๋์ฒดํ๋ ๊ฑด ์๋ค. ์ด์ ํน์ ์ต์ปค๋ก ์ค์์ดํ๋๋ ๊ฒ ์ซ๋ค๋ฉด, confirmValueChange๋ก ์ธ๋ถ์กฐ์ ์ ํ ๊ฒ ์๋๋ผ ์ต์ปค ํฌ์ธํธ ๋ชฉ๋ก์์ ์ ๊ฑฐ๋ฅผ ํด๋ฒ๋ฆฌ๋ผ๊ณ ํ๋ค.
์ด์ ๋ง๊ฒ ์ฝ๋๋ฅผ ์ ๋ฐ์ดํธํ๊ฒ ๋ค.
enum class DragValue { Start, Center, End }
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun AnchoredDraggableBox() {
val density = LocalDensity.current
// ์ต์ปค ์ ์
val anchors = with(density) {
DraggableAnchors {
DragValue.Start at -250.dp.toPx()
DragValue.Center at 0f
DragValue.End at 250.dp.toPx()
}
}
// AnchoredDraggableState ์ ์ธ
val state = remember {
AnchoredDraggableState(
initialValue = DragValue.Center
)
}
// AnchoredDraggableState์ ์ต์ปค ์ฐ๊ฒฐ (์ด๊ธฐํ)
LaunchedEffect(Unit) {
state.updateAnchors(anchors)
}
if (!state.offset.isNaN()) { // ๋ถ๊ธฐ๋ฌธ์ผ๋ก ์ต์ปค ์ฐ๊ฒฐ (์ด๊ธฐํ) ์ ๋ฌด ํ์ธ ํ Box() ํธ์ถ
Box(
Modifier
.offset {
IntOffset(
x = 0,
y = state.offset.roundToInt()
)
}
.width(200.dp)
.height(200.dp)
.background(Color.LightGray)
.anchoredDraggable(
state = state,
orientation = Orientation.Vertical,
flingBehavior = AnchoredDraggableDefaults.flingBehavior(
state = state,
positionalThreshold = { distance -> distance * 0.5f },
animationSpec = spring()
)
)
) {
Text(
"""
Swipe me!
current: ${state.currentValue}
settled: ${state.settledValue}
""".trimIndent()
)
}
}
}
Box() ์ธ๋ถ์ ์ฝ๋ ์ค๋ช
AnchoredDraggableState ์์ฑ์ด ๋งค์ฐ ๊ฐ์ํ๋์๋ค. ๋, ์ต์ปค ํฌ์ธํธ๋ฅผ AnchoredDraggableState.updateAnchors()๋ฅผ ํตํด ์ถ๊ฐํ๋ ๊ฒ ๊ธฐ๋ณธ๊ฐ์ด ๋์๋ค (์ฌ์ ํ ์์ฑ์์ ๋ฃ์ด๋ ๋๊ธด ํ๋ค). ์ ์ฝ๋์์๋ updateAnchors()๋ฅผ LaunchedEfftect()๋ฅผ ํตํด ๋น๋๊ธฐ์ ์ผ๋ก ๋ฃ์ด์ฃผ๊ณ ์๋ค. ์ด ๋น๋๊ธฐ ์ฝ๋ ๋๋ฌธ์ Box()๋ฅผ if๋ฌธ์ผ๋ก ๊ฐ์๋ค. ์ต์ปค ํฌ์ธํธ๊ฐ ์ด๊ธฐํ๋์ง ์์ ์ํ์์ Box()๋ฅผ ์์ฑํ ์๋ ์๊ธฐ ๋๋ฌธ์ด๋ค.
Box() ๋ด๋ถ์ ์ฝ๋ ์ค๋ช
coerceIn()์ ์ฐ์ง ์์๋ ์์ฐ๊ฑฐ๋ฆฌ์ง ์๊ธฐ์ ์ ๊ฑฐํ๋ค. ์ด์ ์ ๋๋ฉ์ด์ ๊ด๋ จ ์ฝ๋๋ anchoredDraggable() ์์ผ๋ก ๋ค์ด๊ฐ๋ค. anchoredDraggable()์ flingBehavior ํ๋กํผํฐ๊ฐ ์ ๋๋ฉ์ด์ ์ ๋ด๋นํ๋ค. ์ฌ๊ธฐ์ AnchoredDraggableDefaults.flingBehavior๋ฅผ ๋ฃ์ด ์ ๋๋ฉ์ด์ ์ ์ง์ ํด์ฃผ์๋ค. flingBehavior ํ๋กํผํฐ๋ nullable์ด๋ผ ๋น์๋ ๋์ํ๋ค. ๋ฆฌํฉํ ๋งํ๋ ๊น์, Text()์ ํ์ฌ ์ํ๋ ํ์ํ๊ฒ ๋ง๋ค์๋ค.
#5-8 ์ ์ฒด ์์ค์ฝ๋
android-practice/pointer-input/AnchoredDraggableExample at master · Kanmanemone/android-practice
Contribute to Kanmanemone/android-practice development by creating an account on GitHub.
github.com
#5-8์ ์ฝ๋ ์ ๋ฐ์ดํธ๋ฅผ ์ ์ฉํ๋ค.
'๊นจ์ ๊ฐ๋ ๐ > Android' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Android] Module ๊ตฌ์กฐ (0) | 2025.09.15 |
|---|---|
| [Android] App layout - Custom layouts (0) | 2025.02.27 |
| [Android] UI architecture - Phase์ State (1) | 2025.02.27 |
| [Android] UI architecture - Phases (0) | 2025.02.27 |
| [Android] App layout - ๊ธฐ์ด (0) | 2025.02.27 |