簡體   English   中英

如何使用觸摸事件在 Jetpack Compose Canvas 上繪圖?

[英]How to draw on Jetpack Compose Canvas using touch events?

這是問答式的問題,因為我一直在尋找帶有 Jetpack Canvas 的繪圖示例,但是關於 stackoverflow 的問題, 這個另一個問題,我發現使用pointerInteropFilter進行繪圖,如 View 的onTouchEvent MotionEvent ,根據文檔不建議這樣做

一個特殊的 PointerInputModifier,它提供對最初分派給 Compose 的底層 MotionEvent 的訪問。 首選pointerInput並僅將其用於與使用 MotionEvents 的現有代碼的互操作。

雖然此 Modifier 的主要目的是允許任意代碼訪問派發給 Compose 的原始 MotionEvent,但為了完整起見,提供了類似物以允許任意代碼與系統交互,就像它是一個 Android 視圖一樣。

編輯

自從我發布這個答案已經有一段時間了,當我從這個問題中得到反饋時,以前的答案對初學者來說有點令人困惑,所以我簡化了它,這個手勢的庫和更多可以在github repo中找到。

我們需要運動狀態,就像 View 的第一個

enum class MotionEvent {
    Idle, Down, Move, Up
}

需要空閑狀態才能在 Up 狀態下保持狀態,因為如果發生任何重組,您的 Canvas 會以 Up 狀態重組,這會導致不需要的繪圖甚至崩潰。

路徑、當前觸摸位置和觸摸狀態

var motionEvent by remember { mutableStateOf(MotionEvent.Idle) }
// This is our motion event we get from touch motion
var currentPosition by remember { mutableStateOf(Offset.Unspecified) }
// This is previous motion event before next touch is saved into this current position
var previousPosition by remember { mutableStateOf(Offset.Unspecified) }

previousPosition是可選的,我使用它是因為我想在使用指針移動時使用path.quadraticBezierTo而不是 path.lineTo 繪制平滑線

用於創建觸摸事件的修飾符。 Modifier.clipToBounds()是為了防止在 Canvas 之外繪制。

val drawModifier = Modifier
    .fillMaxWidth()
    .height(300.dp)
    .clipToBounds()
    .background(Color.White)
    .pointerMotionEvents(
        onDown = { pointerInputChange: PointerInputChange ->
            currentPosition = pointerInputChange.position
            motionEvent = MotionEvent.Down
            pointerInputChange.consume()
        },
        onMove = { pointerInputChange: PointerInputChange ->
            currentPosition = pointerInputChange.position
            motionEvent = MotionEvent.Move
            pointerInputChange.consume()
        },
        onUp = { pointerInputChange: PointerInputChange ->
            motionEvent = MotionEvent.Up
            pointerInputChange.consume()
        },
        delayAfterDownInMillis = 25L
    )

我寫的Modifier.pointerMotionEvents自定義手勢庫是onTouchEvent的對應物,它可以在上面的github repo上找到,這里有關於手勢的詳細解釋,如果你不想的話,你可以輕松地構建自己的手勢。 View 的 onTouchEvent 上發生第一次觸摸后的延遲,在我的設備上大約為 16 毫秒,這是我測量的最快的,我也在 Compose 上添加了手勢,因為當用戶最初快速移動指針時,Canvas 無法處理向下事件。

並將此修改器應用於畫布並根據當前狀態和位置移動或繪制

Canvas(modifier = drawModifier) {


    when (motionEvent) {
        MotionEvent.Down -> {
            path.moveTo(currentPosition.x, currentPosition.y)
            previousPosition = currentPosition
        }

        MotionEvent.Move -> {
            path.quadraticBezierTo(
                previousPosition.x,
                previousPosition.y,
                (previousPosition.x + currentPosition.x) / 2,
                (previousPosition.y + currentPosition.y) / 2

            )
            previousPosition = currentPosition
        }

        MotionEvent.Up -> {
            path.lineTo(currentPosition.x, currentPosition.y)
            currentPosition = Offset.Unspecified
            previousPosition = currentPosition
            motionEvent = MotionEvent.Idle
        }

        else -> Unit
    }

    drawPath(
        color = Color.Red,
        path = path,
        style = Stroke(width = 4.dp.toPx(), cap = StrokeCap.Round, join = StrokeJoin.Round)
    )
}

在此處輸入圖像描述

完整繪圖應用程序的 Github 存儲庫也可在此處獲得。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM