Aby uzyskać optymalną wydajność rysowania, użyj metod startStroke()
, addToStroke()
i finishStroke()
klasy InProgressStrokesView
, przesyłając obiekty MotionEvent
jako dane wejściowe.
Konfigurowanie komponentu interfejsu użytkownika
Zintegruj
InProgressStrokesView
ze swoją hierarchią widoków.<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>
Tworzenie obiektu InProgressStrokesView
W metodzie [
onCreate()
][ink-draw-include6] aktywności lub fragmentu uzyskaj odwołanie doInProgressStrokesView
i ustaw odbiornik dotyku do zarządzania danymi wejściowymi użytkownika.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) }
Obsługa zdarzeń dotyku
Po skonfigurowaniu komponentów interfejsu możesz rozpocząć rysowanie na podstawie zdarzeń dotknięcia.
Działanie
MotionEvent
metoda
InProgressStrokesView
Opis
Rozpoczęcie renderowania obrysu
Kontynuuj renderowanie obrysu
Zakończ renderowanie obrysu
Zaimplementuj odrzucenie dłoni; anuluj ruch
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 } }
Obsługa zakończonych ruchów pędzla
Po wywołaniu
finishStroke()
kreska jest oznaczona jako ukończona. Proces finalizacji nie jest jednak natychmiastowy. Zarys jest w pełni przetwarzany i staje się dostępny dla aplikacji wkrótce po wywołaniu funkcjifinishStroke()
, zwłaszcza gdy nie ma żadnych innych zarysów w trakcie. Dzięki temu wszystkie operacje rysowania są zakończone, zanim ślad zostanie przekazany klientowi jako ukończony.Gotowe pociągnięcia możesz pobrać na 2 sposoby:
- Zaimplementuj interfejs
InProgressStrokesFinishedListener
w aktywności lub ViewModel i zarejestruj detektora wInProgressStrokesView
za pomocąaddFinishedStrokesListener
. - Aby bezpośrednio uzyskać wszystkie zakończone pociągnięcia, użyj metody
getFinishedStrokes()
InProgressStrokesView
.
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) } }
Po pobraniu gotowych linii możesz użyć
ViewStrokeRenderer
jako abstrakcji wyższego poziomu utworzonej na podstawieCanvasStrokeRenderer
. Może to jeszcze bardziej uprościć proces renderowania w hierarchii widoków.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, ... } } }
- Zaimplementuj interfejs