Per ottenere un rendimento ottimale dei disegni, utilizza i metodi
startStroke()
,
addToStroke()
,
e
finishStroke()
della classe
InProgressStrokesView
, passando come input gli oggetti
MotionEvent
.
Configurare il componente dell'interfaccia utente
Integra
InProgressStrokesView
nella gerarchia delle visualizzazioni.<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>
Eseguire l'inizializzazione di InProgressStrokesView
All'interno del metodo [
onCreate()
][ink-draw-include6] dell'attività o del frammento, otteni un riferimento aInProgressStrokesView
e stabilisci un listener tocco per gestire l'input dell'utente.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) }
Gestire gli eventi touch
Dopo aver definito i componenti dell'interfaccia utente, ora puoi avviare il disegno in base agli eventi di tocco.
Azione
MotionEvent
InProgressStrokesView
methodDescrizione
Inizia il rendering del tratto
Continuare il rendering del tratto
Completare il rendering del tratto
Implementa il rifiuto della palma; annulla il tratto
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 } }
Gestire i tratti finali
Dopo aver chiamato
finishStroke()
, la traccia viene contrassegnata come completata. Tuttavia, la procedura di finalizzazione non è immediata. Il tratto viene elaborato completamente e diventa accessibile alla tua applicazione poco dopo la chiamata difinishStroke()
, in particolare quando non sono in corso altri tratti. In questo modo, tutte le operazioni di disegno vengono completate prima che il tratto venga consegnato al cliente come completato.Per recuperare i tratti finiti, hai due opzioni:
- Implementa l'interfaccia
InProgressStrokesFinishedListener
all'interno della tua attività o ViewModel e registra l'ascoltatore conInProgressStrokesView
conaddFinishedStrokesListener
. - Utilizza il metodo
getFinishedStrokes()
diInProgressStrokesView
per ottenere direttamente tutti i tratti finiti.
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) } }
Una volta recuperati i tratti finali, puoi utilizzare
ViewStrokeRenderer
come un'astrazione di livello superiore basata suCanvasStrokeRenderer
. In questo modo puoi semplificare ulteriormente la procedura di rendering all'interno della gerarchia delle visualizzazioni.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, ... } } }
- Implementa l'interfaccia