如要達到最佳繪圖效能,請使用 InProgressStrokesView
類別的 startStroke()
、addToStroke()
和 finishStroke()
方法,並將 MotionEvent
物件做為輸入內容。
設定 UI 元件
將
InProgressStrokesView
整合至檢視區塊階層。<FrameLayout> <ScrollView android:id="@+id/my_content" android:width="match_parent" android:height="match_parent" > <!-- Your content here. --> </ScrollView> <androidx.ink.authoring.InProgressStrokesView android:id="@+id/in_progress_strokes_view" android:width="match_parent" android:height="match_parent" /> </FrameLayout>
例項化 InProgressStrokesView
在活動或片段的 [
onCreate()
][ink-draw-include6] 方法中,取得InProgressStrokesView
的參照,並建立觸控事件監聽器來管理使用者輸入內容。class MyActivity : View.OnTouchListener { private lateinit var contentView: ScrollView private lateinit var inProgressStrokesView: InProgressStrokesView private lateinit var predictor: MotionEventPredictor // ... other variables override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) predictor = MotionEventPredictor.newInstance(contentView) contentView = findViewById(R.id.my_content) contentView.setOnTouchListener(touchListener) inProgressStrokesView = findViewById(R.id.in_progress_strokes_view) } // ... (touchListener implementation) }
處理觸控事件
建立 UI 元件後,您現在可以根據觸控事件啟動繪圖。
MotionEvent
動作InProgressStrokesView
方法說明
開始顯示筆劃
繼續算繪筆劃
完成筆劃算繪
實作防手掌誤觸功能;取消筆觸
class MyActivity : View.OnTouchListener { private lateinit var contentView: ScrollView private lateinit var inProgressStrokesView: InProgressStrokesView private var pointerId = -1 private var strokeId: InProgressStrokeId? = null private lateinit var predictor: MotionEventPredictor override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) contentView = findViewById(R.id.my_content) predictor = MotionEventPredictor.create(contentView) contentView.setOnTouchListener(touchListener) inProgressStrokesView = findViewById(R.id.in_progress_strokes_view) } private val touchListener = { view: View, event: MotionEvent -> predictor.record(event) when (event.actionMasked) { MotionEvent.ACTION_DOWN -> { // First pointer - treat it as inking. view.requestUnbufferedDispatch(event) val pointerIndex = event.actionIndex pointerIdToStrokeId[event.getPointerId(pointerIndex)] = inProgressStrokesView.startStroke(event, pointerId) return true } MotionEvent.ACTION_POINTER_DOWN -> { val stroke = strokeId ?: return false inProgressStrokesView.cancelStroke(stroke, event) strokeId = null pointerId = -1 return false } MotionEvent.ACTION_MOVE -> { val predictedEvent = predictor.predict() try { for (pointerIndex in 0 until pointerCount) { val strokeId = pointerIdToStrokeId[event.getPointerId(pointerIndex)] ?: continue inProgressStrokesView.addToStroke(event, pointerId, strokeId, predictedEvent) } finally { predictedEvent?.recycle() } } } MotionEvent.ACTION_UP -> { val pointerIndex = event.actionIndex val strokeId = pointerIdToStrokeId[event.getPointerId(pointerIndex)] ?: return false inProgressStrokesView.finishStroke(event, pointerId, strokeId) return true } MotionEvent.ACTION_CANCEL -> { val pointerIndex = event.actionIndex val strokeId = pointerIdToStrokeId[event.getPointerId(pointerIndex)] ?: return false inProgressStrokesView.cancelStroke(strokeId, event) return true } } return false } }
處理完成的筆劃
呼叫
finishStroke()
時,系統會將筆劃標示為完成。不過,最終程序不會立即生效。筆劃已完整處理,在呼叫finishStroke()
後不久即可供應用程式存取,尤其是在沒有其他進行中的筆劃時。這樣可確保所有繪圖作業在筆劃傳送給用戶端前都已完成「完成」。如要擷取已完成的筆劃,有兩種方法可供選擇:
- 在活動或 ViewModel 中實作
InProgressStrokesFinishedListener
介面,並使用addFinishedStrokesListener
將事件監聽器註冊至InProgressStrokesView
。 - 使用
InProgressStrokesView
的getFinishedStrokes()
方法,直接取得所有已完成的筆劃。
class MyActivity : ComponentActivity(), InProgressStrokesFinishedListener { ... private val finishedStrokesState = mutableStateOf(emptySet<Stroke>()) override fun onCreate(savedInstanceState: Bundle?) { ... inProgressStrokesView.addFinishedStrokesListener(this) } // ... (handle touch events) @UiThread override fun onStrokesFinished(strokes: Map<InProgressStrokeId, Stroke>) { finishedStrokesState.value += strokes.values inProgressStrokesView.removeFinishedStrokes(strokes.keys) } }
擷取完成的筆劃後,您可以使用
ViewStrokeRenderer
做為建構在CanvasStrokeRenderer
之上的高階抽象概念。這可進一步簡化檢視區塊階層中的轉譯程序。class DrawingView(context: Context) : View(context) { private val viewStrokeRenderer = ViewStrokeRenderer(myCanvasStrokeRenderer, this) override fun onDraw(canvas: Canvas) { viewStrokeRenderer.drawWithStrokes(canvas) { scope -> canvas.scale(myZoomLevel) canvas.rotate(myRotation) canvas.translate(myPanX, myPanY) scope.drawStroke(myStroke) // Draw other objects including more strokes, apply more transformations, ... } } }
- 在活動或 ViewModel 中實作