Unterstützung erweiterter Eingabestiftfunktionen

Mit dem Eingabestift können Nutzer bequem und punktgenau mit Apps interagieren, z. B. Notizen, Skizzen, Arbeiten mit Produktivitäts-Apps, zum Entspannen und für Spaß mit Spielen und Unterhaltungs-Apps.

Android und ChromeOS bieten eine Vielzahl von APIs, mit denen du Apps mit Eingabestift optimal nutzen kannst. Die Klasse MotionEvent liefert Informationen zur Nutzerinteraktion mit dem Bildschirm, z. B. zum Druck des Eingabestifts, zur Ausrichtung, zur Neigung, zum Bewegen des Mauszeigers und zur Handflächenerkennung. Bibliotheken mit niedriger Latenz und Bewegungsvorhersagen verbessern das Rendern mit Eingabestiften auf dem Bildschirm und sorgen so für ein ganz natürliches Erlebnis mit Stift und Papier.

MotionEvent

Die Klasse MotionEvent repräsentiert Nutzereingabeinteraktionen wie die Position und Bewegung von Touchpointern auf dem Bildschirm. Bei Eingabe des Eingabestifts zeigt MotionEvent auch Daten zu Druck, Ausrichtung, Neigung und dem Mauszeiger an.

Ereignisdaten

Richten Sie für den Zugriff auf MotionEvent-Daten in aufrufbasierten Apps einen onTouchListener ein:

Kotlin

val onTouchListener = View.OnTouchListener { view, event ->
  // Process motion event.
}

Java

View.OnTouchListener listener = (view, event) -> {
  // Process motion event.
};

Der Listener empfängt MotionEvent-Objekte vom System, sodass Ihre App sie verarbeiten kann.

Ein MotionEvent-Objekt stellt Daten zu den folgenden Aspekten eines UI-Ereignisses bereit:

  • Aktionen: Physische Interaktion mit dem Gerät – Berühren des Bildschirms, Bewegen eines Zeigers über die Bildschirmoberfläche, Bewegen eines Zeigers über die Bildschirmoberfläche
  • Zeiger: Kennungen von Objekten, die mit dem Bildschirm interagieren (Finger, Eingabestift, Maus)
  • Achse: Datentyp – x- und y-Koordinaten, Druck, Neigung, Ausrichtung und Mouseover (Entfernung)

Aktionen

Um die Eingabestiftunterstützung zu implementieren, müssen Sie verstehen, welche Aktion der Nutzer ausführt.

MotionEvent bietet eine Vielzahl von ACTION-Konstanten, die Bewegungsereignisse definieren. Die wichtigsten Aktionen für den Eingabestift sind:

Aktion Beschreibung
ACTION_DOWN
ACTION_POINTER_DOWN
Zeiger hat Kontakt mit dem Bildschirm hergestellt.
ACTION_MOVE (Aktionsverschiebung) Zeiger bewegt sich auf dem Bildschirm.
ACTION_UP
ACTION_POINTER_UP
Zeiger liegt nicht mehr auf dem Bildschirm
AKTION_ABBRECHEN Wenn eine vorherige oder aktuelle Bewegung abgebrochen werden soll.

Ihre App kann verschiedene Aufgaben ausführen, z. B. das Starten eines neuen Strichs, wenn ACTION_DOWN geschieht, das Zeichnen des Strichs mit ACTION_MOVE, und das Fertigstellen des Strichs, wenn „ACTION_UP“ ausgelöst wird.

Die Gruppe der MotionEvent-Aktionen von ACTION_DOWN bis ACTION_UP für einen bestimmten Zeiger wird als Bewegungssatz bezeichnet.

Zeiger

Die meisten Bildschirme arbeiten mit Multi-Touch-Funktion: Das System weist jedem Finger, Eingabestift, jeder Maus oder einem anderen Zeigeobjekt, das mit dem Bildschirm interagiert, einen Zeiger zu. Mit einem Zeigerindex können Sie Achseninformationen für einen bestimmten Zeiger abrufen, z. B. die Position des ersten Fingers, der den Bildschirm berührt, oder die Position des zweiten.

Zeigerindexe reichen von null bis die Anzahl der von MotionEvent#pointerCount() zurückgegebenen Zeiger minus 1.

Auf die Achsenwerte der Zeiger kann mit der Methode getAxisValue(axis, pointerIndex) zugegriffen werden. Wenn der Zeigerindex weggelassen wird, gibt das System den Wert für den ersten Zeiger zurück, Zeiger Null (0).

MotionEvent-Objekte enthalten Informationen zum verwendeten Zeigertyp. Sie können den Zeigertyp abrufen, indem Sie durch die Zeigerindexe iterieren und die Methode getToolType(pointerIndex) aufrufen.

Weitere Informationen zu Zeigern finden Sie unter Multi-Touch-Gesten handhaben.

Eingabestift-Eingaben

Mit TOOL_TYPE_STYLUS können Sie nach Eingabestifteingaben filtern:

Kotlin

val isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex)

Java

boolean isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex);

Der Eingabestift kann auch melden, dass er als Radierer mit TOOL_TYPE_ERASER verwendet wird:

Kotlin

val isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex)

Java

boolean isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex);

Daten zur Eingabestiftachse

ACTION_DOWN und ACTION_MOVE liefern Achsendaten zum Eingabestift, d. h. X- und Y-Koordinaten, Druck, Ausrichtung, Neigung und Mausbewegung.

Um den Zugriff auf diese Daten zu ermöglichen, stellt die MotionEvent API getAxisValue(int) bereit, wobei der Parameter eine der folgenden Achsenkennungen ist:

Axis Rückgabewert von getAxisValue()
AXIS_X X-Koordinate eines Bewegungsereignisses.
AXIS_Y Y-Koordinate eines Bewegungsereignisses.
AXIS_PRESSURE Bei Touchscreens oder Touchpads wird der Druck durch einen Finger, einen Eingabestift oder einen anderen Zeiger aufgewendet. Bei einer Maus oder einem Trackball: 1, wenn die primäre Taste gedrückt wird, andernfalls 0.
AXIS_ORIENTATION Bei einem Touchscreen oder Touchpad die Ausrichtung eines Fingers, Eingabestifts oder eines anderen Zeigers relativ zur vertikalen Ebene des Geräts.
AXIS_TILT Der Neigungswinkel des Eingabestifts in Radiant.
AXIS_DISTANCE Abstand des Eingabestifts vom Bildschirm

MotionEvent.getAxisValue(AXIS_X) gibt beispielsweise die x-Koordinate für den ersten Zeiger zurück.

Weitere Informationen finden Sie unter Multi-Touch-Gesten handhaben.

Position

Sie können die x- und y-Koordinaten eines Zeigers mit den folgenden Aufrufen abrufen:

Zeichnung eines Eingabestifts auf dem Bildschirm mit abgebildeten x- und y-Koordinaten.
Abbildung 1. X- und Y-Bildschirmkoordinaten eines Eingabestiftzeigers.

Luftdruck

Sie können den Zeigerdruck mit den folgenden Aufrufen abrufen:

getAxisValue(AXIS_PRESSURE) oder getPressure() für den ersten Mauszeiger.

Der Druckwert für Touchscreens oder Touchpads liegt zwischen 0 (kein Druck) und 1. Je nach Bildschirmkalibrierung können jedoch auch höhere Werte zurückgegeben werden.

Strichstärken des Eingabestifts, die ein Kontinuum von niedrigem bis hohem Druck darstellt. Die Kontur ist auf der linken Seite schmal und schwach, was auf geringen Druck hinweist. Der Strich wird von links nach rechts breiter und dunkler, bis er ganz rechts am breitesten und dunkelsten ist. Dies zeigt den höchsten Druck an.
Abbildung 2. Druckdarstellung: niedriger Druck links, hoher Druck rechts.

Ausrichtung

Die Ausrichtung gibt an, in welche Richtung der Eingabestift zeigt.

Die Ausrichtung des Zeigers kann mithilfe von getAxisValue(AXIS_ORIENTATION) oder getOrientation() (für den ersten Zeiger) abgerufen werden.

Bei einem Eingabestift wird die Ausrichtung als Radiantenwert zwischen 0 und pi (Π) im Uhrzeigersinn oder von 0 bis -pi gegen den Uhrzeigersinn zurückgegeben.

Mithilfe der Ausrichtung kannst du einen echten Pinsel implementieren. Wenn der Eingabestift beispielsweise einen flachen Pinsel darstellt, hängt seine Breite von der Ausrichtung des Eingabestifts ab.

Abbildung 3: Eingabestift, der etwa nach links zeigt – 0,57 Radiant

Neigen

Die Neigung misst die Neigung des Eingabestifts im Verhältnis zum Bildschirm.

Die Neigung gibt den positiven Winkel des Eingabestifts in Radiant zurück, wobei Null senkrecht zum Bildschirm und Π/2 flach auf der Oberfläche ist.

Der Neigungswinkel kann mit getAxisValue(AXIS_TILT) abgerufen werden (keine Kurzform für den ersten Zeiger).

Mithilfe der Neigung lassen sich so nah wie möglich reale Werkzeuge reproduzieren, z. B. die Schattierung mit einem geneigten Bleistift.

Eingabestift ist um etwa 40 Grad zur Bildschirmoberfläche geneigt.
Abbildung 4: Eingabestift um etwa 0, 785 Radiant (45 Grad ausgehend von der Senkrechten) geneigt.

Hover

Den Abstand des Eingabestifts zum Bildschirm kannst du mit getAxisValue(AXIS_DISTANCE) abrufen. Die Methode gibt einen Wert von 0, 0 (Kontakt mit dem Bildschirm) und höhere Werte zurück, wenn sich der Eingabestift vom Bildschirm wegbewegt. Der Abstand zwischen dem Bildschirm und der Spitze des Eingabestifts hängt vom Hersteller des Bildschirms und des Eingabestifts ab. Da Implementierungen variieren können, sollten Sie sich für app-kritische Funktionen nicht auf genaue Werte verlassen.

Mit dem Mauszeiger über den Eingabestift kann eine Vorschau der Größe des Pinsels angezeigt oder angezeigt werden, dass eine Schaltfläche ausgewählt wird.

Abbildung 5: Eingabestift, der über einem Bildschirm schwebt Die App reagiert auch dann, wenn der Eingabestift die Bildschirmoberfläche nicht berührt.

Hinweis:In der Funktion „Compose“ finden Sie eine Reihe von Modifikatorelementen, mit denen Sie den Status von UI-Elementen ändern können:

  • hoverable: Konfigurieren Sie die Komponente so, dass sie sich über Eingabe- und Exit-Ereignisse über den Mauszeiger bewegen kann.
  • indication: Zeichnet visuelle Effekte für diese Komponente, wenn Interaktionen stattfinden.

Manuelles Ablehnen, Navigation und unerwünschte Eingaben

Manchmal werden bei Multi-Touch-Bildschirmen unerwünschte Berührungen erfasst, z. B. wenn ein Nutzer seine Hand auf dem Bildschirm ablegt, um sich beim Schreiben zu unterstützen. Die Entsperrung per Handzeichen wird erkannt und Sie erhalten eine Benachrichtigung, dass die letzte Einrichtung (MotionEvent) abgebrochen werden sollte.

Daher müssen Sie einen Verlauf der Nutzereingaben speichern, damit die unerwünschten Berührungen vom Bildschirm entfernt und die legitimen Nutzereingaben neu gerendert werden können.

ACTION_CANCEL und FLAG_CANCELED

ACTION_CANCEL und FLAG_CANCELED sollen Sie darüber informieren, dass der vorherige MotionEvent-Satz vom letzten ACTION_DOWN abgebrochen werden soll. So können Sie beispielsweise den letzten Strich in einer Zeichen-App für einen bestimmten Zeiger rückgängig machen.

AKTION_ABBRECHEN

In Android 1.0 (API-Level 1) hinzugefügt

ACTION_CANCEL gibt an, dass die vorherige Gruppe von Bewegungsereignissen abgebrochen werden soll.

ACTION_CANCEL wird ausgelöst, wenn Folgendes erkannt wird:

  • Touch-Gesten für die Navigation
  • Ablehnung von Handflächen

Wenn ACTION_CANCEL ausgelöst wird, sollten Sie den aktiven Cursor mit getPointerId(getActionIndex()) identifizieren. Entfernen Sie dann die mit diesem Zeiger erstellte Kontur aus dem Eingabeverlauf und rendern Sie die Szene noch einmal.

FLAG_ABGEBROCHEN

In Android 13 (API-Level 33) hinzugefügt

FLAG_CANCELED gibt an, dass der Zeiger durch eine unbeabsichtigte Berührung des Nutzers nach oben gegangen ist. Die Markierung wird normalerweise gesetzt, wenn der Nutzer versehentlich den Bildschirm berührt, z. B. indem er das Gerät hält oder die Handfläche auf den Bildschirm legt.

So greifen Sie auf den Flag-Wert zu:

Kotlin

val cancel = (event.flags and FLAG_CANCELED) == FLAG_CANCELED

Java

boolean cancel = (event.getFlags() & FLAG_CANCELED) == FLAG_CANCELED;

Wenn das Flag gesetzt ist, müssen Sie den letzten Satz MotionEvent ausgehend von der letzten ACTION_DOWN von diesem Punkt aus rückgängig machen.

Wie bei ACTION_CANCEL kann der Mauszeiger mit getPointerId(actionIndex) gefunden werden.

Abbildung 6: Durch die Eingabe des Eingabestifts und die Berührung der Handfläche werden MotionEvent-Sätze erstellt. Die Berührung per Handzeichen wird abgebrochen und das Display wird neu gerendert.

Vollbild, randloses Display und Navigationsgesten

Wenn eine App im Vollbildmodus angezeigt wird und am Rand handlungsrelevante Elemente enthält, wie z. B. der Canvas einer Zeichnungs- oder Notizen-App, kann es zu unerwünschten Berührungen auf dem Canvas kommen, wenn Sie vom unteren Bildschirmrand wischen, um die Navigation anzuzeigen oder die App in den Hintergrund zu verschieben.

Abbildung 7: Wische eine Wischgeste, um eine App in den Hintergrund zu verschieben.

Um zu verhindern, dass Gesten unerwünschte Berührungen in Ihrer App auslösen, können Sie Einsätze und ACTION_CANCEL verwenden.

Weitere Informationen finden Sie oben im Abschnitt Handschriftablehnung, Navigation und unerwünschte Eingaben.

Verwenden Sie die Methode setSystemBarsBehavior() und BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE von WindowInsetsController, um zu verhindern, dass Navigationsgesten unerwünschte Touch-Ereignisse verursachen:

Kotlin

// Configure the behavior of the hidden system bars.
windowInsetsController.systemBarsBehavior =
    WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

Java

// Configure the behavior of the hidden system bars.
windowInsetsController.setSystemBarsBehavior(
    WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
);

Weitere Informationen zur Einfügung und zum Verwalten von Gesten finden Sie unter:

Niedrige Latenz

Die Latenz ist die Zeit, die von der Hardware, dem System und der Anwendung benötigt wird, um Nutzereingaben zu verarbeiten und zu rendern.

Latenz = Hardware- und Betriebssystemeingabeverarbeitung + Anwendungsverarbeitung + Systemzusammensetzung + Hardware-Rendering

Durch die Latenz bleibt der gerenderte Strich hinter der Position des Eingabestifts zurück. Die Lücke zwischen dem gerenderten Strich und der Position des Eingabestifts stellt die Latenz dar.
Abbildung 8. Durch die Latenz bleibt der gerenderte Strich hinter der Position des Eingabestifts zurück.

Quelle der Latenz

  • Registrieren des Eingabestifts mit Touchscreen (Hardware): Erste kabellose Verbindung, wenn der Eingabestift und das Betriebssystem miteinander kommunizieren, um registriert und synchronisiert zu werden.
  • Berührungsabtastrate (Hardware): Die Häufigkeit, mit der ein Touchscreen pro Sekunde prüft, ob ein Zeiger die Oberfläche berührt. Der Bereich liegt zwischen 60 und 1.000 Hz.
  • Eingabeverarbeitung (App): Anwenden von Farben, grafischen Effekten und Transformationen auf Nutzereingaben.
  • Grafikrendering (Betriebssystem und Hardware): Austausch von Puffern, Hardwareverarbeitung.

Grafiken mit niedriger Latenz

Die Jetpack-Grafikbibliothek mit niedriger Latenz reduziert die Verarbeitungszeit zwischen Nutzereingabe und Bildschirmrendering.

Die Bibliothek reduziert die Verarbeitungszeit, indem sie Multi-buffer-Rendering vermeidet und eine Rendering-Technik für Frontbuffer nutzt, bei der direkt in den Bildschirm geschrieben wird.

Rendering des Frontzwischenspeichers

Der Frontpuffer ist der Arbeitsspeicher, den der Bildschirm für das Rendering verwendet. So können Apps direkt auf dem Bildschirm zeichnen. Dank der niedrigen Latenzbibliothek können Anwendungen direkt im Front-Zwischenspeicher gerendert werden. Dadurch wird die Leistung verbessert, weil der Austausch von Zwischenspeichern verhindert wird, wie es häufig beim Rendering mit mehreren Zwischenspeichern oder beim Rendering mit doppelt Zwischenspeichern der Fall ist.

Die App schreibt in den Bildschirmzwischenspeicher und liest aus dem Bildschirmzwischenspeicher.
Abbildung 9. Pufferrendering auf der Vorderseite.
Die Anwendung schreibt in den Multi-Zwischenspeicher, der mit Bildschirmpuffer ausgetauscht wird. Die App liest aus dem Bildschirmzwischenspeicher.
Abbildung 10. Rendering mit mehreren Zwischenspeichern

Frontbuffer-Rendering ist zwar eine großartige Technik, um einen kleinen Bereich des Bildschirms zu rendern, ist jedoch nicht für die Aktualisierung des gesamten Bildschirms gedacht. Beim Rendern des Frontbuffers rendert die App Inhalte in einen Zwischenspeicher, aus dem die Anzeige Daten liest. Dies kann zu Rendering-Artefakten oder zu Reißen führen(siehe unten).

Die Bibliothek mit niedriger Latenz ist ab Android 10 (API-Level 29) und auf ChromeOS-Geräten mit Android 10 (API-Level 29) und höher verfügbar.

Abhängigkeiten

Die Bibliothek mit niedriger Latenz stellt die Komponenten für die Implementierung des Frontbuffer-Renderings bereit. Die Bibliothek wird als Abhängigkeit in die Moduldatei build.gradle der App eingefügt:

dependencies {
    implementation "androidx.graphics:graphics-core:1.0.0-alpha03"
}

GLFrontBufferRenderer-Callbacks

Die Bibliothek mit niedriger Latenz umfasst die GLFrontBufferRenderer.Callback-Schnittstelle, die die folgenden Methoden definiert:

Die Bibliothek mit niedriger Latenz berücksichtigt nicht den Datentyp, den Sie mit GLFrontBufferRenderer verwenden.

Die Bibliothek verarbeitet die Daten jedoch als Strom von Hunderten von Datenpunkten. Gestalten Sie Ihre Daten daher so, dass die Speichernutzung und die Speicherzuweisung optimiert werden.

Rückrufe

Implementieren Sie GLFrontBufferedRenderer.Callback und überschreiben Sie onDrawFrontBufferedLayer() und onDrawDoubleBufferedLayer(), um Rendering-Callbacks zu aktivieren. GLFrontBufferedRenderer verwendet die Callbacks, um deine Daten bestmöglich zu rendern.

Kotlin

val callback = object: GLFrontBufferedRenderer.Callback<DATA_TYPE> {

   override fun onDrawFrontBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       param: DATA_TYPE
   ) {
       // OpenGL for front buffer, short, affecting small area of the screen.
   }

   override fun onDrawMultiDoubleBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       params: Collection<DATA_TYPE>
   ) {
       // OpenGL full scene rendering.
   }
}

Java

GLFrontBufferedRenderer.Callback<DATA_TYPE> callbacks =
    new GLFrontBufferedRenderer.Callback<DATA_TYPE>() {
        @Override
        public void onDrawFrontBufferedLayer(@NonNull EGLManager eglManager,
            @NonNull BufferInfo bufferInfo,
            @NonNull float[] transform,
            DATA_TYPE data_type) {
                // OpenGL for front buffer, short, affecting small area of the screen.
        }

    @Override
    public void onDrawDoubleBufferedLayer(@NonNull EGLManager eglManager,
        @NonNull BufferInfo bufferInfo,
        @NonNull float[] transform,
        @NonNull Collection<? extends DATA_TYPE> collection) {
            // OpenGL full scene rendering.
    }
};
Instanz von GLFrontBufferedRenderer deklarieren

Bereiten Sie die GLFrontBufferedRenderer vor, indem Sie die SurfaceView und die Callbacks angeben, die Sie zuvor erstellt haben. GLFrontBufferedRenderer optimiert das Rendering im Vordergrund und den doppelten Zwischenspeicher mithilfe deiner Callbacks:

Kotlin

var glFrontBufferRenderer = GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks)

Java

GLFrontBufferedRenderer<DATA_TYPE> glFrontBufferRenderer =
    new GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks);
Rendering

Das Rendering des Front-Zwischenspeichers beginnt, wenn Sie die renderFrontBufferedLayer()-Methode aufrufen, die den onDrawFrontBufferedLayer()-Callback auslöst.

Das doppelte Rendering wird fortgesetzt, wenn Sie die Funktion commit() aufrufen, die den onDrawMultiDoubleBufferedLayer()-Callback auslöst.

Im folgenden Beispiel wird der Prozess im vorderen Zwischenspeicher (schnelles Rendering) gerendert, wenn der Nutzer mit dem Zeichnen auf dem Bildschirm beginnt (ACTION_DOWN) und den Mauszeiger darüber bewegt (ACTION_MOVE). Der Vorgang wird im doppelten Zwischenspeicher gerendert, wenn der Zeiger die Oberfläche des Bildschirms verlässt (ACTION_UP).

Mit requestUnbufferedDispatch() können Sie festlegen, dass das Eingabesystem Bewegungsereignisse nicht im Batch verarbeiten soll, sondern sie stattdessen sendet, sobald sie verfügbar sind:

Kotlin

when (motionEvent.action) {
   MotionEvent.ACTION_DOWN -> {
       // Deliver input events as soon as they arrive.
       view.requestUnbufferedDispatch(motionEvent)
       // Pointer is in contact with the screen.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_MOVE -> {
       // Pointer is moving.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_UP -> {
       // Pointer is not in contact in the screen.
       glFrontBufferRenderer.commit()
   }
   MotionEvent.CANCEL -> {
       // Cancel front buffer; remove last motion set from the screen.
       glFrontBufferRenderer.cancel()
   }
}

Java

switch (motionEvent.getAction()) {
   case MotionEvent.ACTION_DOWN: {
       // Deliver input events as soon as they arrive.
       surfaceView.requestUnbufferedDispatch(motionEvent);

       // Pointer is in contact with the screen.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE);
   }
   break;
   case MotionEvent.ACTION_MOVE: {
       // Pointer is moving.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE);
   }
   break;
   case MotionEvent.ACTION_UP: {
       // Pointer is not in contact in the screen.
       glFrontBufferRenderer.commit();
   }
   break;
   case MotionEvent.ACTION_CANCEL: {
       // Cancel front buffer; remove last motion set from the screen.
       glFrontBufferRenderer.cancel();
   }
   break;
}

Gebote und Verbote beim Rendering

Dos

Kleine Teile des Bildschirms, Handschrift, Zeichnung, Skizzieren.

Nicht erlaubt

Vollbildaktualisierung, Schwenken, Zoomen. Kann zu Tränen führen.

Tränend

Wenn der Bildschirm aktualisiert wird, während der Bildschirmzwischenspeicher gleichzeitig geändert wird, entstehen Tränen. Ein Teil des Bildschirms zeigt neue Daten, ein anderer Teil alte Daten.

Der obere und untere Teil des Android-Bildes ist aufgrund von Risse beim Aktualisieren des Bildschirms falsch ausgerichtet.
Abbildung 11. Tränen, wenn der Bildschirm von oben nach unten aktualisiert wird.

Bewegungsvorhersage

Die Jetpack-Bibliothek für Bewegungsvorhersagen reduziert die wahrgenommene Latenz, indem sie den Strichpfad des Nutzers schätzt und temporäre, künstliche Punkte für den Renderer bereitstellt.

Die Bibliothek für Bewegungsvorhersagen erhält echte Nutzereingaben als MotionEvent-Objekte. Die Objekte enthalten Informationen zu x- und y-Koordinaten, Druck und Zeit, die vom Bewegungsprädiktor genutzt werden, um zukünftige MotionEvent-Objekte vorherzusagen.

Die vorhergesagten MotionEvent-Objekte sind nur Schätzungen. Vorhergesagte Ereignisse können die wahrgenommene Latenz reduzieren, aber vorhergesagte Daten müssen durch tatsächliche MotionEvent-Daten ersetzt werden, sobald sie empfangen wurden.

Die Bibliothek für Bewegungsvorhersagen ist ab Android 4.4 (API-Level 19) und auf ChromeOS-Geräten mit Android 9 (API-Level 28) und höher verfügbar.

Durch die Latenz bleibt der gerenderte Strich hinter der Position des Eingabestifts zurück. Die Lücke zwischen Strich und Eingabestift wird mit Vorhersagepunkten gefüllt. Die verbleibende Lücke ist die wahrgenommene Latenz.
Abbildung 12. Durch Bewegungsvorhersage reduzierte Latenz.

Abhängigkeiten

Die Bewegungsvorhersagebibliothek ermöglicht die Implementierung der Vorhersage. Die Bibliothek wird als Abhängigkeit in die Moduldatei build.gradle der App eingefügt:

dependencies {
    implementation "androidx.input:input-motionprediction:1.0.0-beta01"
}

Implementierung

Die Bibliothek für Bewegungsvorhersagen enthält die Schnittstelle MotionEventPredictor, die die folgenden Methoden definiert:

  • record(): speichert MotionEvent-Objekte als Datensatz der Nutzeraktionen
  • predict(): gibt einen vorhergesagten MotionEvent zurück
Instanz von MotionEventPredictor deklarieren

Kotlin

var motionEventPredictor = MotionEventPredictor.newInstance(view)

Java

MotionEventPredictor motionEventPredictor = MotionEventPredictor.newInstance(surfaceView);
Daten in den Predictor einspeisen

Kotlin

motionEventPredictor.record(motionEvent)

Java

motionEventPredictor.record(motionEvent);
Vorhersage

Kotlin

when (motionEvent.action) {
   MotionEvent.ACTION_MOVE -> {
       val predictedMotionEvent = motionEventPredictor?.predict()
       if(predictedMotionEvent != null) {
            // use predicted MotionEvent to inject a new artificial point
       }
   }
}

Java

switch (motionEvent.getAction()) {
   case MotionEvent.ACTION_MOVE: {
       MotionEvent predictedMotionEvent = motionEventPredictor.predict();
       if(predictedMotionEvent != null) {
           // use predicted MotionEvent to inject a new artificial point
       }
   }
   break;
}

Tipps zur Bewegungsvorhersage

Dos

Vorhersagepunkte werden entfernt, wenn ein neuer vorhergesagter Punkt hinzugefügt wird.

Nicht erlaubt

Verwenden Sie für das endgültige Rendering keine Vorhersagepunkte.

Notizen-Apps

Mit ChromeOS kann deine App bestimmte Aktionen zum Erstellen von Notizen deklarieren.

Informationen zum Registrieren einer App als Notizen-App unter ChromeOS finden Sie unter Eingabekompatibilität.

Weitere Informationen zum Registrieren einer App als Notizen-App auf Android-Geräten finden Sie unter Notizen-App erstellen.

Mit Android 14 (API-Level 34) wurde der Intent ACTION_CREATE_NOTE eingeführt, mit dem deine App eine Notizaktivität auf dem Sperrbildschirm starten kann.

Digitale Tintenerkennung mit ML Kit

Mit der digitalen Tintenerkennung von ML Kit kann Ihre App handschriftlichen Text auf einer digitalen Oberfläche in Hunderten von Sprachen erkennen. Sie können auch Skizzen klassifizieren.

ML Kit bietet die Klasse Ink.Stroke.Builder zum Erstellen von Ink-Objekten, die von Modellen für maschinelles Lernen verarbeitet werden können, um Handschrift in Text umzuwandeln.

Zusätzlich zur Handschrifterkennung kann das Modell auch Touch-Gesten erkennen, z. B. Löschen und Einkreisen.

Weitere Informationen finden Sie unter Digitale Tintenerkennung.

Weitere Informationen

Entwicklerleitfäden

Codelabs