En los diseños basados en vistas, debes controlar las entradas táctiles de los usuarios dentro de un elemento InProgressStrokesView, además de MotionEventPredictor.
Para lograr un rendimiento de dibujo óptimo, usa los métodos startStroke(), addToStroke() y finishStroke() de la clase InProgressStrokesView, y pasa objetos MotionEvent como entrada:
Configura el componente de IU
Para diseños basados en vistas, agrega
InProgressStrokesViewa tu jerarquía de vistas.<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>Instanciar
InProgressStrokesViewDentro del método
onCreate()de tu actividad o fragmento, obtén una referencia aInProgressStrokesViewy configura un objeto de escucha táctil para administrar la entrada del usuario.Dentro del método [
onCreate()][ink-draw-include6] de tu actividad o fragmento, obtén una referencia aInProgressStrokesViewy establece un objeto de escucha táctil para administrar la entrada del usuario.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) }Cómo controlar eventos táctiles
Una vez que estableciste los componentes de la IU, puedes iniciar el dibujo en función de los eventos táctiles.
MotionEventactionMétodo
InProgressStrokesViewDescripción
Comienza a renderizar el trazo.
Extiende el trazo
Finaliza las entradas y prepárate para finalizar la geometría del trazo
Cómo cancelar el trazo
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 } }Cómo controlar los trazos terminados
Después de
finishStroke(), el trazo está casi completo. El trazo se procesa por completo y tu aplicación puede acceder a él una vez que no haya otros trazos en curso. Esto garantiza que todas las operaciones de dibujo se completen antes de que el trazo se entregue al cliente.Para recuperar los trazos terminados, tienes dos opciones:
- Implementa la interfaz
InProgressStrokesFinishedListeneren tu actividad o ViewModel, y registra el objeto de escucha conInProgressStrokesViewllamando aaddFinishedStrokesListener. - Llama a
InProgressStrokesView.getFinishedStrokes()para obtener todos los trazos terminados directamente.
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 vez que recuperes los trazos terminados, puedes usar
ViewStrokeRendererpara dibujarlos: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 la interfaz