Strich zeichnen

Verwenden Sie für eine optimale Zeichenleistung die Methoden startStroke(), addToStroke() und finishStroke() der Klasse InProgressStrokesView und geben Sie MotionEvent-Objekte als Eingabe an.

  1. UI-Komponente einrichten

    InProgressStrokesView in die Ansichtshierarchie einbinden.

    <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>
    

  2. InProgressStrokesView instanziieren

    Rufen Sie in der [onCreate()][ink-draw-include6]-Methode Ihrer Aktivität oder Ihres Fragments einen Verweis auf InProgressStrokesView ab und legen Sie einen Touch-Listener zum Verwalten der Nutzereingabe fest.

    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)
    }
    

  3. Touch-Ereignisse verarbeiten

    Nachdem Sie die UI-Komponenten eingerichtet haben, können Sie jetzt das Zeichnen basierend auf Touch-Ereignissen initiieren.

    MotionEvent-Aktion

    InProgressStrokesView-Methode

    Beschreibung

    ACTION_DOWN

    startStroke()

    Stroke-Rendering starten

    ACTION_MOVE

    addToStroke()

    Stroke-Rendering fortsetzen

    ACTION_UP

    finishStroke()

    Stroke-Rendering abschließen

    ACTION_CANCEL oder FLAG_CANCELED

    cancelStroke()

    Implementieren Sie die Handflächenerkennung und brechen Sie den Strich ab.

    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
      }
    }
    

  4. Abgeschlossene Striche verarbeiten

    Wenn finishStroke() aufgerufen wird, wird der Strich als abgeschlossen markiert. Der Abschlussvorgang dauert jedoch einige Zeit. Der Strich wird vollständig verarbeitet und ist kurz nach dem Aufruf von finishStroke() für Ihre Anwendung verfügbar, insbesondere wenn keine anderen Striche ausgeführt werden. So wird sichergestellt, dass alle Zeichenvorgänge abgeschlossen sind, bevor der Strich als fertig an den Client übergeben wird.

    Sie haben zwei Möglichkeiten, fertige Striche abzurufen:

    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)
      }
    }
    

    Nachdem Sie die fertigen Striche abgerufen haben, können Sie die ViewStrokeRenderer als Abstraktion auf höherer Ebene verwenden, die auf der CanvasStrokeRenderer basiert. Dies kann den Rendering-Prozess in Ihrer Ansichtshierarchie weiter vereinfachen.

    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, ...
        }
      }
    }