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
InProgressStrokesViewnella 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>Creare un'istanza di InProgressStrokesView
All'interno del metodo [
onCreate()][ink-draw-include6] dell'attività o del frammento, otteni un riferimento aInProgressStrokesViewe 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
Una volta stabiliti i componenti dell'interfaccia utente, puoi avviare il disegno in base agli eventi di tocco.
Azione
MotionEventMetodo
InProgressStrokesViewDescrizione
Inizia il rendering del tratto
Continua a eseguire il rendering del tratto
Finalizzare il rendering del tratto
Implementa il rifiuto del palmo; 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 completati
Quando chiami
finishStroke(), il segno viene contrassegnato per il completamento. Tuttavia, il processo di finalizzazione non è immediato. 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. Ciò garantisce che tutte le operazioni di disegno siano concluse prima che il tratto venga passato al client come finito.Per recuperare i tratti finiti, hai due opzioni:
- Implementa l'interfaccia
InProgressStrokesFinishedListenerall'interno della tua attività o ViewModel e registra l'ascoltatore conInProgressStrokesViewconaddFinishedStrokesListener. - Utilizza il metodo
getFinishedStrokes()diInProgressStrokesViewper ottenere direttamente tutti i tratti finali.
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
ViewStrokeRenderercome 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