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, obtenez une référence àInProgressStrokesView
et établissez un écouteur tactile pour gérer les entrées utilisateur.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) }
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) } }
Une fois que vous avez récupéré les traits terminés, vous pouvez utiliser
ViewStrokeRenderer
en tant qu'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