๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Android

[Android] Pointer input - Gesture

interfacer_han 2025. 2. 8. 17:56

#1 ๊ฐœ์š”

#1-1 ์ด์ „ ๊ฒŒ์‹œ๊ธ€

 

[Android] Pointer input - PointerInputChange, PointerEvent

#1 ๊ฐœ์š” ๋™์ž‘ ์ดํ•ดํ•˜๊ธฐ  |  Jetpack Compose  |  Android Developers์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋™์ž‘ ์ดํ•ดํ•˜๊ธฐ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €

kenel.tistory.com

์œ„์˜ ๊ฒŒ์‹œ๊ธ€์—์„œ ์ด์–ด์ง„๋‹ค. ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€์—์„œ ๋จผ์ € PointerInputChange ๋ฐ PointerEvent์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ํ•ด์•ผ ๋ณธ ๊ฒŒ์‹œ๊ธ€์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.
 

#1-2 ๊ณต์‹ ๋ฌธ์„œ

 

๋™์ž‘ ์ดํ•ดํ•˜๊ธฐ  |  Jetpack Compose  |  Android Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋™์ž‘ ์ดํ•ดํ•˜๊ธฐ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ์š”. ์ดํ•ดํ•ด์•ผ ํ•  ๋ช‡ ๊ฐ€์ง€ ์šฉ์–ด์™€ ๊ฐœ๋…์ด ์žˆ

developer.android.com

์ด์ „ ๊ฒŒ์‹œ๊ธ€๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๋‚˜์˜ ์–ธ์–ด๋กœ ์ •๋ฆฌํ•˜๊ณ , ์ƒ˜ํ”Œ ์•ฑ๋„ ๋งŒ๋“ค์–ด๋ดค๋‹ค.
 

#2 Gesture

#2-1 Gesture๋Š” ๋ณ„๋ช…์ด๋‹ค

2๊ฐœ ์ด์ƒ์˜ ์ผ๋ จ์˜ PointerEvent ์กฐํ•ฉ์— ๋ถ™์ด๋Š” ๋ณ„๋ช…์ด๋‹ค. ๋ณ„๋„์˜ ํด๋ž˜์Šค๋กœ ์กด์žฌํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Tab Gesture๋Š” PointerEvent.type.toString() == Press์ธ PointerEvent์— ๋’ค์ด์–ด PointerEvent.type.toString() == Release์ธ PointerEvent๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ์ด๋ฅผ ํŠน๋ณ„ํžˆ Tab Gesture๋ผ ๋ถ€๋ฅธ๋‹ค. ์ด์™€ ๋น„์Šทํ•˜๊ฒŒ Drag Gesture๋‚˜ Transform Gesture ๋“ฑ์ด ์žˆ์œผ๋ฉฐ, ์ผ๋ จ์˜ PointerEvent ์กฐํ•ฉ์„ ๊ฐ์ง€ํ•˜๋Š” ์‚ฌ์šฉ์ž ์ง€์ • Gesture๋„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
 

#2-2 ๊ธฐ๋ณธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ œ๊ณต ์ œ์Šค์ฒ˜

Gesture(์ œ์Šค์ฒ˜) ์œ ํ˜• ์ œ์Šค์ฒ˜๋ฅผ ๋ถ€์—ฌํ•˜๋Š” Modifier์˜ ํ™•์žฅ ํ•จ์ˆ˜
Tap, Press clickablecombinedClickableselectabletoggleabletriStateToggleable
Scrolling horizontalScrollverticalScrollscrollable
Dragging draggableanchoredDraggable
Multi-touch Gesture transformable

ํ‘œ์˜ 2์—ด์— ์žˆ๋Š” ๋ชจ๋“  ์š”์†Œ๋Š” Modifier์˜ ํ™•์žฅ ํ•จ์ˆ˜๋‹ค. ์ฆ‰, @Composable์ด ๊ฐ€์ง€๋Š” modifier ์ธ์ˆ˜์— ์ € ํ™•์žฅ ํ•จ์ˆ˜๋“ค์„ ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹ํ•˜์—ฌ ๋„ฃ์–ด์ฃผ๋ฉด Gesture๋ฅผ '๋ถ€์—ฌ'(= ํŠน์ • PointerEvent์˜ ์กฐํ•ฉ์˜ ๊ฐ์ง€ + ์›ํ•˜๋Š” ๋™์ž‘ ๋ช…์„ธ)ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ‘œ์— ์žˆ๋Š” transformable์€ ์ด๋ฆ„์—์„œ ์–ด๋–ค ๊ธฐ๋Šฅ์ธ์ง€ ์ง๊ด€์  ํŒŒ์•…์ด ํž˜๋“ค๋‹ค (์˜๋ฏธ๊ถŒ ์‚ฌ๋žŒ์€ ๊ฐ€๋Šฅํ•˜๋ ค๋‚˜?). transformable์€ ์ง€๋„ ์•ฑ์—์„œ ์ง€๋„ ํƒ์ƒ‰, ์ปดํฌ๋„ŒํŠธ ํšŒ์ „, ์คŒ ์ธ/์•„์›ƒ ๋“ฑ์˜ ๋ฉ€ํ‹ฐ ํ„ฐ์น˜๋ฅผ ์š”ํ•˜๋Š” ์ œ์Šค์ฒ˜ ๊ตฌํ˜„์„ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.
 

#2-3 ์‚ฌ์šฉ์ž ์ •์˜ ์ œ์Šค์ฒ˜

Text(
    text = componentName,
    modifier = Modifier
        .background(Color.LightGray)
        .pointerInput(Unit) { 
            awaitPointerEventScope {
                while (true) {
                    val event = awaitPointerEvent() 
                    // event๋ฅผ ๊ฐ€์ง€๊ณ  ๋ฌด์–ธ๊ฐˆ ํ•˜๋Š” ์ฝ”๋“œ
                }
            }
        },
    fontSize = 48.sp,
)

์œ„ ์ฝ”๋“œ๋Š” ์ด์ „ ๊ฒŒ์‹œ๊ธ€์—์„œ ์“ด ์ฝ”๋“œ์˜ ์ผ๋ถ€๋ถ„์ด๋‹ค. ์œ„์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉ์ž ์ •์˜ ์ œ์Šค์ฒ˜๋„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ๋‚ด๊ฐ€ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์€ ํŠน์ • PointerEvent์˜ ์กฐํ•ฉ์„ ๊ฐ์ง€ํ•˜๊ณ , ๊ฐ์ง€๋์„ ๋•Œ์˜ ๋™์ž‘์„ ์œ„ ์ฝ”๋“œ์˜ ์ฃผ์„ ๋ถ€๋ถ„์— ๋„ฃ๋Š” ์‹์œผ๋กœ ๋ง์ด๋‹ค.
 
ํ•˜์ง€๋งŒ, awaintPointerEvent()๋ฅผ ์ด์šฉํ•ด ์‚ฌ์šฉ์ž ์ •์˜ ์ œ์Šค์ฒ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฑด, ๋„ˆ๋ฌด๋‚˜ ์›์‹œ(raw)์ ์ด๋ผ ๊ตฌํ˜„์ด ๋ณต์žกํ•˜๋‹ค. ์ด๋Ÿฐ ๋ถ€๋‹ด์„ ๋œ์–ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ Jetpack Compose์—์„  detectTapGesture(), detectDragGestures()๊ฐ™์€ Gesture ๊ฐ์ง€๋ฅผ ์œ„ํ•œ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

#2-4 Gesture ๊ฐ์ง€ ํ•จ์ˆ˜ ๋ชฉ๋ก

Gesture(์ œ์Šค์ฒ˜) ์œ ํ˜• ์ œ์Šค์ฒ˜๋ฅผ ๊ฐ์ง€ํ•˜๋Š” PointerInputScope์˜ ํ™•์žฅ ํ•จ์ˆ˜
Tap, Double Tap, Press, Long-press detectTapGestures()
Drag detectDragGestures(), detectVerticalDragGestures(), detectHorizontalDragGestures(), detectDragGesturesAfterLongPress()
Transform detectTransformGestures()

๊ฐ detect...Gestures() ํ•จ์ˆ˜๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ํ›„์ˆ ํ•  awaitEachGesture()๋กœ ๊ฐ์‹ธ์—ฌ์žˆ๋‹ค.
 

#2-5 awaitEachGesture()

Jetpack Compose์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฑด, Gesture ๊ฐ์ง€ ํ•จ์ˆ˜ ๋ฟ๋งŒ์ด ์•„๋‹ˆ๋‹ค. ์œ„์—์„œ ํ•œ๋ฒˆ ๋ณด์—ฌ์คฌ๋˜ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์จ๋ณด๊ฒ ๋‹ค.
 

Text(
    text = componentName,
    modifier = Modifier
        .background(Color.LightGray)
        .pointerInput(Unit) { 
            awaitPointerEventScope {
                while (true) {
                    val event = awaitPointerEvent() 
                    // event๋ฅผ ๊ฐ€์ง€๊ณ  ๋ฌด์–ธ๊ฐˆ ํ•˜๋Š” ์ฝ”๋“œ
                }
            }
        },
    fontSize = 48.sp,
)

์ด ์ฝ”๋“œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ„์†Œํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.
 

Text(
    text = componentName,
    modifier = Modifier
        .background(Color.LightGray)
        .pointerInput(Unit) {
            awaitEachGesture {
                val event = awaitPointerEvent()
                // event๋ฅผ ๊ฐ€์ง€๊ณ  ๋ฌด์–ธ๊ฐˆ ํ•˜๋Š” ์ฝ”๋“œ
            }
        },
    fontSize = 48.sp,
)

์ฆ‰, awaitEachGesture()๋Š” awaitPointerEventScope() ๋ฐ while(true)๋ฅผ ๋Œ€์ฒดํ•œ๋‹ค. ํ•˜์ง€๋งŒ, awaitEachGesture()๋Š” ๋ณด๋‹ค ๊ณ ์ˆ˜์ค€์˜ ์˜์—ญ(Scope)์œผ๋กœ์„œ, ๋” ๊ฐ„ํŽธํ•œ(์•”์‹œ์ ์ธ) ์ฝ”๋“œ๋ฅผ ์งค ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค€๋‹ค. ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ, awaitEachGesure() ์†์—์„  ๊ฐ Gesture๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด ์ž๋™์œผ๋กœ ๋‹ค์Œ Gesture๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. awaitPointerEventScope() ๋ฐ while(true) ๊ตฌ์กฐ์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ Gesture๊ฐ€ ์–ธ์ œ ์‹œ์ž‘ํ•˜๊ณ  ์–ธ์ œ ๋๋‚˜๋Š” ์ง€์— ๋Œ€ํ•œ ์ฝ”๋“œ๋ฅผ ์ผ์ผํžˆ ์งœ์•ผํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋Œ€์กฐ์ ์ด๋‹ค.
 
๋ฌผ๋ก , ๋” ์•”์‹œ์ ์ธ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•˜๋‹ค๋Š” ๊ฒƒ์€ ๋œ ์„ธ์‹ฌํ•˜๋‹ค๋Š” ์–˜๊ธฐ๋„ ๋œ๋‹ค. ์•„์ฃผ ๋ฏธ์„ธํ•œ PointerEvent ์ œ์–ด๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด awaitPointerEventScope()๋ฅผ ๋‹ค์‹œ ์จ์•ผํ•  ์ˆ˜๋„ ์žˆ์„ ํ…Œ๋‹ค.
 

#2-6 Gesture ๊ฐ์ง€ ํ•จ์ˆ˜์˜ ์‚ฌ์šฉ๋ก€

Box(
    modifier = Modifier
        .size(100.dp)
        .background(Color.Red)
        .pointerInput(Unit) {
            detectTapGestures(onTap = { offset -> log = "Tapped at $offset" })
        }
        .pointerInput(Unit) {
            detectDragGestures { _, _ -> log = "Dragging" }
        }
) {
    Text("box content")
}

๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹
Gesture ๊ฐ์ง€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋Š” ์œ„์™€ ๊ฐ™๋‹ค. ํ•˜๋‚˜์˜ pointerInput()์—๋Š” ํ•˜๋‚˜์˜ Gesture ๊ฐ์ง€ ํ•จ์ˆ˜๋งŒ์„ ๋„ฃ์–ด์•ผ ํ•œ๋‹ค (์ฐธ์กฐ: pointerInput()์˜ ์ค‘๋ณต ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹).

 

์œ„์˜ ์ฝ”๋“œ์™€๋Š” ๋‹ฌ๋ฆฌ, ํ•˜๋‚˜์˜ pointerInput()์—, detectTapGestures()์™€ detectDragGestures()๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ๋ชฝ๋•… ๋„ฃ์—ˆ๋‹ค๊ณ  ์น˜์ž. ์ด๋Ÿฌ๋ฉด, detectDragGestures()๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๊ณ  ์˜ค์ง detectTapGestures()๋งŒ ์‹คํ–‰๋œ๋‹ค. ์œ„์—์„œ ์„ค๋ช…ํ•œ ๋ฐ”์™€ ๊ฐ™์ด detect...Gestures() ํ•จ์ˆ˜๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ awaitEachGesture()๋กœ ๊ฐ์‹ธ์—ฌ์žˆ๊ณ , ๊ทธ awaitEachGesture๋Š” while(true)์˜ ๋™์ž‘์„ ํฌํ•จํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๊ฒฝ์šฐ์—” pointerInput() ๋‚ด์—์„œ ์‚ฌ์šฉ์ž์˜ 'Drag' ๋™์ž‘์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์—†๋‹ค. ์ด ๊ฒฝ์šฐ์˜ pointerInput()์€ ์˜ค์ง 'Tap' ๋™์ž‘์˜ ๊ฐ์ง€๋งŒ์„ ์œ„ํ•ด ๋Œ€๊ธฐํ•  ๊ฒƒ์ด๋‹ค.
 
์•”์‹œ์  ์†Œ๋น„
๋˜ ๊ฐ detect...Gesture() ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜ ์ข…๋ฃŒ ์ „, PointerEvent๋ฅผ '์†Œ๋น„๋จ' ์ƒํƒœ๋กœ ์—…๋ฐ์ดํŠธํ•œ๋‹ค (ํ”„๋กœ๊ทธ๋ž˜๋จธ ์ž…์žฅ์—์„œ๋Š” PointerEvent๊ฐ€ ์•”์‹œ์ ์œผ๋กœ ์†Œ๋น„๋˜๋Š” ์…ˆ์ด๋‹ค).
 
์—ฌ๋‹ด
pointerInput()์— ์ ˆ๋Œ€ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๊ฐ’์ธ Unit์„ ๋„ฃ์—ˆ์œผ๋ฏ€๋กœ, pointerInput() ์ฝ”๋“œ ๋ธ”๋ก์€ Recomposition๋•Œ๋„ ์žฌ์‹คํ–‰๋˜์ง€ ์•Š๊ณ  ์ญ‰ ์œ ์ง€๋  ๊ฒƒ์ด๋‹ค.
 

#3 ์‚ฌ์šฉ์ž ์ง€์ • Gesture ๊ตฌํ˜„

#3-1 ๊ฐœ์š”

๋”๋ธ” ํด๋ฆญ ์‹œ์˜ ๋™์ž‘์€ Jetpack Compose์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜์ง€๋งŒ, ํŠธ๋ฆฌํ”Œ ํด๋ฆญ์€ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋ณธ ๊ฒŒ์‹œ๊ธ€์—์„œ ๋ฐฐ์šด ์ง€์‹์„ ๋ฐ”ํƒ•์œผ๋กœ ์ปค์Šคํ…€ Gesture๋กœ์„œ 'ํŠธ๋ฆฌํ”Œ ํด๋ฆญ'์„ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ๋‹ค.
 

#3-2 ํ•ต์‹ฌ ์ฝ”๋“œ

@SuppressLint("ModifierFactoryUnreferencedReceiver")
fun Modifier.addTripleClickGesture1(context: Context): Modifier {
    return Modifier.composed { // composed๋Š” State๋ฅผ ๊ฐ€์ง€๋Š” Modifier์˜ ํ™•์žฅ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒํ•จ
        var tapCount by remember { mutableIntStateOf(0) } // ํด๋ฆญ ํšŸ์ˆ˜
        var lastTapTime by remember { mutableLongStateOf(0L) } // ๋งˆ์ง€๋ง‰ ํด๋ฆญ ์‹œ๊ฐ„

        Modifier.pointerInput(Unit) {
            detectTapGestures {
                val currentTime = System.currentTimeMillis()
                tapCount = if (currentTime - lastTapTime < 500) { // 500๋ฐ€๋ฆฌ์ดˆ ์ด๋‚ด
                    ++tapCount
                } else {
                    1
                }
                lastTapTime = currentTime

                if (tapCount >= 3) { // ํŠธ๋ฆฌํ”Œ ํด๋ฆญ ๊ฐ์ง€
                    Toast.makeText(context, "Triple Clicked!", Toast.LENGTH_SHORT).show()
                    tapCount = 0 // ์ดˆ๊ธฐํ™”
                }
            }
        }
    }
}

addTripleClickGesture1()์€ onClick ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณด์œ ํ•œ Button() ๋“ฑ์— ์ ์šฉํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด, Button()์—์„œ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ์šฐ์„ ์ ์œผ๋กœ ์†Œ๋น„ํ•˜๊ธฐ์—, detectTapGestures()์— ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋–จ์–ด์ง€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๋‚˜๋Š” addTripleClickGesture1()๋ฅผ Box()์˜ modifier์— ์ ์šฉํ–ˆ๋‹ค.

ChatGPT๊ฐ€ ์•Œ๋ ค์ค€, Coroutines์„ ํ™œ์šฉํ•œ ๊ตฌํ˜„

๋”๋ณด๊ธฐ
@SuppressLint("ModifierFactoryUnreferencedReceiver")
fun Modifier.addTripleClickGesture2(context: Context): Modifier {
    return Modifier.composed {
        var tapCount by remember { mutableIntStateOf(0) } // ํด๋ฆญ ํšŸ์ˆ˜
        val coroutineScope = rememberCoroutineScope()

        Modifier.pointerInput(Unit) {
            detectTapGestures {
                tapCount++
                coroutineScope.launch {
                    delay(500) // 500๋ฐ€๋ฆฌ ๋™์•ˆ ๊ธฐ๋‹ค๋ฆผ (์—ฐ์† ํด๋ฆญ ํ™•์ธ)
                    if (tapCount >= 3) { // ํŠธ๋ฆฌํ”Œ ํด๋ฆญ ๊ฐ์ง€
                        Toast.makeText(context, "Triple Clicked!", Toast.LENGTH_SHORT).show()
                    }
                    tapCount = 0 // ์ดˆ๊ธฐํ™”
                }
            }
        }
    }
}

addTripleClickGesture2()๋Š” onClick ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณด์œ ํ•œ Button() ๋“ฑ์— ์ ์šฉํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด, Button()์—์„œ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ์šฐ์„ ์ ์œผ๋กœ ์†Œ๋น„ํ•˜๊ธฐ์—, detectTapGestures()์— ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋–จ์–ด์ง€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๋‚˜๋Š” addTripleClickGesture1()๋ฅผ Box()์˜ modifier์— ์ ์šฉํ–ˆ๋‹ค.

 

#3-3 ์™„์„ฑ๋œ ์•ฑ

 

android-practice/pointer-input/TripleClickGesture at master · Kanmanemone/android-practice

Contribute to Kanmanemone/android-practice development by creating an account on GitHub.

github.com

 

#4 ์š”์•ฝ

Gesture๋Š” ํŠน์ • PointerEvent ์กฐํ•ฉ์˜ ๋ณ„๋ช…์ด๋ฉฐ, Gesture ์ œ์–ด๋ฅผ ์œ„ํ•œ ์—ฌ๋Ÿฌ ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•œ๋‹ค.