Pour obtenir des performances de dessin optimales, utilisez les méthodes startStroke()
, addToStroke()
et finishStroke()
de la classe InProgressStrokesView
, en transmettant les objets MotionEvent
en entrée.
Configurer le composant d'interface utilisateur
Intégrez
InProgressStrokesView
à la hiérarchie des vues.<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>
Instancier InProgressStrokesView
Dans la méthode [
onCreate()
][ink-draw-include6] de votre activité ou fragment, obtenir une référence àInProgressStrokesView
et établir une écouteur tactile pour gérer les entrées utilisateurclass 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) }
Gérer les événements tactiles
Après avoir défini les composants de l'interface utilisateur, vous pouvez maintenant lancer le dessin en fonction des événements tactiles.
Action
MotionEvent
Méthode
InProgressStrokesView
Description
Démarrer l'affichage du trait
Poursuivre le rendu du trait
Finaliser le rendu du trait
Implémenter le rejet de la paume de la main ; annuler le trait
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 } }
Gérer les traits terminés
Lorsque vous appelez
finishStroke()
, le trait est marqué comme terminé. Toutefois, le processus de finalisation n'est pas instantané. Le trait est entièrement traité et devient accessible à votre application peu de temps après l'appel definishStroke()
, en particulier lorsqu'il n'y a pas d'autres traits en cours. Cela garantit que toutes les opérations de dessin sont terminées avant que le trait ne soit remis au client en tant que terminé.Pour récupérer les traits terminés, vous avez deux options :
- Implémentez l'interface
InProgressStrokesFinishedListener
dans votre activité ou ViewModel, puis enregistrez l'écouteur avecInProgressStrokesView
avecaddFinishedStrokesListener
. - Utilisez la méthode
getFinishedStrokes()
deInProgressStrokesView
pour obtenir directement tous les traits terminés.
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) } }
Après avoir récupéré les mouvements terminés, vous pouvez utiliser la
ViewStrokeRenderer
en tant que une abstraction de niveau supérieur basée surCanvasStrokeRenderer
Cela peut simplifier davantage le processus d'affichage dans votre hiérarchie des vues.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, ... } } }
- Implémentez l'interface