Android und ChromeOS bieten eine Vielzahl von APIs, mit denen Sie Apps erstellen können,
wie der Eingabestift besonders gut funktioniert. Die
MotionEvent
-Klassen-Offenlegungen
Informationen zur Interaktion des Eingabestifts mit dem Bildschirm, z. B. Druck des Eingabestifts,
Ausrichtung, Neigung, Mouseover und Handflächenerkennung. Grafiken und Bewegungen mit niedriger Latenz
verbessern die Darstellung von Eingabestiften
auf dem Bildschirm und bieten
wie mit Stift und Papier.
MotionEvent
Die Klasse MotionEvent
steht für Interaktionen mit Nutzereingaben, z. B. die Position
und Bewegungen der Touchpointer auf dem Bildschirm. Für Eingabe per Eingabestift: MotionEvent
Außerdem werden Druck, Ausrichtung, Neigung und der Mauszeiger darauf angezeigt.
Ereignisdaten
To access MotionEvent
data, add a pointerInput
modifier to components:
@Composable
fun Greeting() {
Text(
text = "Hello, Android!", textAlign = TextAlign.Center, style = TextStyle(fontSize = 5.em),
modifier = Modifier
.pointerInput(Unit) {
awaitEachGesture {
while (true) {
val event = awaitPointerEvent()
event.changes.forEach { println(it) }
}
}
},
)
}
Ein MotionEvent
-Objekt stellt Daten zu den folgenden Aspekten einer UI bereit.
Ereignis:
- Aktionen: physische Interaktion mit dem Gerät, z. B. Berühren des Bildschirms, Bewegen eines Zeigers über die Bildschirmoberfläche, Bewegen eines Zeigers über den Bildschirm Oberfläche
- Zeiger: Kennungen von Objekten, die mit dem Bildschirm interagieren, z. B. Finger, Eingabestift, Maus
- Achse: Datentyp – x- und y-Koordinaten, Druck, Neigung, Ausrichtung und Mauszeiger darauf bewegen (Entfernung)
Aktionen
Wenn Sie die Unterstützung für Eingabestifte implementieren möchten, müssen Sie wissen, welche Aktion der Nutzer ausführt die Leistung zu steigern.
MotionEvent
bietet eine Vielzahl von ACTION
-Konstanten, die Bewegung definieren
Ereignisse. Die wichtigsten Aktionen für den Eingabestift:
Aktion | Beschreibung |
---|---|
ACTION_DOWN ACTION_POINTER_DOWN |
Der Zeiger hat den Bildschirm berührt. |
ACTION_MOVE (Aktion_VERSCHIEBEN) | Zeiger bewegt sich auf dem Bildschirm. |
ACTION_UP ACTION_POINTER_UP |
Zeiger berührt den Bildschirm nicht mehr |
AKTION_ABBRECHEN | Wann der vorherige oder die aktuelle Bewegungssatz abgebrochen werden soll. |
Deine App kann Aufgaben wie das Starten eines neuen Strichs ausführen, wenn ACTION_DOWN
wird die Kontur mit ACTION_MOVE,
gezeichnet und sie wird beendet,
ACTION_UP
wird ausgelöst.
Die Menge der MotionEvent
-Aktionen zwischen ACTION_DOWN
und ACTION_UP
für eine bestimmte
wird als Bewegungssatz bezeichnet.
Mauszeiger
Bei den meisten Bildschirmen wird Multi-Touch-Technologie eingesetzt: Das System weist jedem Finger einen Zeiger zu, ein Eingabestift, eine Maus oder ein anderes Zeigeobjekt, das mit dem Bildschirm interagiert. Ein Cursor können Sie Achseninformationen für einen bestimmten Zeiger abrufen, z. B. den Position des ersten Fingers, der den Bildschirm berührt, oder des zweiten Fingers.
Zeigerindexe reichen von null bis zur Anzahl der Zeiger, die von
MotionEvent#pointerCount()
minus 1.
Auf die Achsenwerte der Zeiger kann mit der Methode getAxisValue(axis,
pointerIndex)
zugegriffen werden.
Wird der Zeigerindex weggelassen, gibt das System den Wert für den ersten
Zeiger, Zeiger Null (0).
MotionEvent
-Objekte enthalten Informationen zum verwendeten Zeigertyp. Ich
können Sie den Zeigertyp abrufen, indem Sie
die Zeigerindexe durchlaufen und
die
getToolType(pointerIndex)
.
Weitere Informationen zu Pointern finden Sie unter Umgang mit Multi-Touch-Gesten Touch-Gesten.
Eingabestift
Sie können nach Eingabestifteingaben filtern,
TOOL_TYPE_STYLUS
:
val isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex)
Der Eingabestift kann auch melden, dass er als Radiergummi verwendet wird.
TOOL_TYPE_ERASER
:
val isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex)
Daten der Eingabestiftachse
ACTION_DOWN
und ACTION_MOVE
stellen die Achsendaten des Eingabestifts bereit, nämlich x und
y-Koordinaten, Druck, Ausrichtung, Neigung und Position des Mauszeigers.
Um den Zugriff auf diese Daten zu ermöglichen, bietet die MotionEvent
API
getAxisValue(int)
,
Hierbei steht der Parameter für eine der folgenden Achsenkennungen:
Axis | Rückgabewert von getAxisValue() |
---|---|
AXIS_X |
X-Koordinate eines Bewegungsereignisses |
AXIS_Y |
Y-Koordinate eines Bewegungsereignisses |
AXIS_PRESSURE |
Auf einem Touchscreen oder Touchpad der Druck, der von einem Finger, einem Eingabestift oder einem anderen Zeiger ausgeübt wird. Bei Maus- oder Trackballs: 1, wenn die Haupttaste gedrückt wird, andernfalls 0. |
AXIS_ORIENTATION |
Bei einem Touchscreen oder Touchpad die Ausrichtung eines Fingers, eines Eingabestifts oder eines anderen Zeigers relativ zur vertikalen Ebene des Geräts. |
AXIS_TILT |
Der Neigungswinkel des Eingabestifts im Bogenmaß. |
AXIS_DISTANCE |
Der Abstand des Eingabestifts zum Bildschirm. |
Zum Beispiel gibt MotionEvent.getAxisValue(AXIS_X)
die X-Koordinate für den
ersten Zeiger.
Siehe auch Umgang mit Multi-Touch-Funktionen Touch-Gesten.
Position
Sie können die x- und y-Koordinaten eines Zeigers mit den folgenden Aufrufen abrufen:
MotionEvent#getAxisValue(AXIS_X)
oderMotionEvent#getX()
MotionEvent#getAxisValue(AXIS_Y)
oderMotionEvent#getY()
Luftdruck
Sie können den Druck des Zeigers mit
MotionEvent#getAxisValue(AXIS_PRESSURE)
oder für den ersten Zeiger,
MotionEvent#getPressure()
Der Druckwert für Touchscreens oder Touchpads liegt zwischen 0 (keine Druck) und 1, aber je nach Bildschirm können höhere Werte zurückgegeben werden. Kalibrierung.
<ph type="x-smartling-placeholder">Ausrichtung
Die Ausrichtung gibt an, in welche Richtung der Eingabestift zeigt.
Die Zeigerausrichtung kann mit getAxisValue(AXIS_ORIENTATION)
oder
getOrientation()
(für den ersten Zeiger).
Bei einem Eingabestift wird die Ausrichtung als Radiantwert zwischen 0 und pi (∂) zurückgegeben. im Uhrzeigersinn oder von 0 bis -pi gegen den Uhrzeigersinn.
Mithilfe der Ausrichtung kannst du einen realen Pinsel implementieren. Wenn zum Beispiel der Parameter der einen flachen Pinsel darstellt, hängt seine Breite vom Ausrichtung des Eingabestifts.
<ph type="x-smartling-placeholder">Neigen
„Neigung“ gibt die Neigung des Eingabestifts relativ zum Bildschirm an.
„Neigung“ gibt den positiven Winkel des Eingabestifts im Bogenmaß zurück, wobei Null gleich senkrecht zum Bildschirm, und hol-Sicht-Position liegt flach auf der Oberfläche.
Der Neigungswinkel kann mit getAxisValue(AXIS_TILT)
abgerufen werden (keine Verknüpfung für
den ersten Zeiger).
Durch Neigen können reale Werkzeuge so nahe wie möglich reproduziert werden, Imitiert die Schattierung mit einem geneigten Bleistift.
<ph type="x-smartling-placeholder">Mauszeiger hierher bewegen
Die Entfernung des Eingabestifts zum Bildschirm wird mit
getAxisValue(AXIS_DISTANCE)
Die Methode gibt einen Wert von 0,0 zurück (Kontakt mit
Bildschirm) einen höheren Wert ein, wenn sich der Eingabestift vom Bildschirm entfernt. Die Mausbewegung
der Abstand zwischen dem Bildschirm und der Spitze des Eingabestifts
Hersteller des Displays und des Eingabestifts. Da Implementierungen
variieren, verlassen Sie sich für anwendungskritische Funktionen nicht auf präzise Werte.
Wenn Sie den Mauszeiger auf einen Eingabestift bewegen, können Sie eine Vorschau der Pinselgröße anzeigen lassen oder angeben, dass ein ausgewählt wird.
<ph type="x-smartling-placeholder">Hinweis:Die Funktion „Compose“ bietet Modifikatoren, die sich auf den interaktiven Status von UI-Elementen auswirken:
hoverable
: Konfigurieren Sie die Komponente so, dass sie mit Zeiger-Eingabe- und -Exit-Ereignissen bewegt werden kann.indication
: Zeichnet visuelle Effekte für diese Komponente bei Interaktionen.
Ablehnen des Palms, Navigation und unerwünschte Eingaben
Manchmal können Multi-Touch-Bildschirme unerwünschte Berührungen registriert werden, z. B. wenn ein
Nutzende lassen ihre Hand auf dem Bildschirm ablesen, um sie beim Schreiben zu unterstützen.
Der Sensor zur Abstoßung des Palms erkennt dieses Verhalten und benachrichtigt Sie, dass
wird der letzte MotionEvent
-Satz abgebrochen.
Daher müssen Sie einen Verlauf der Nutzereingaben aufbewahren, damit die unerwünschten Berührungen können vom Bildschirm entfernt werden und legitime das erneut gerendert wurde.
ACTION_CANCEL und FLAG_CANCELED
ACTION_CANCEL
und
FLAG_CANCELED
sind
Beide sollen Ihnen mitteilen, dass der vorherige MotionEvent
-Satz
der letzten ACTION_DOWN
storniert wurde, sodass Sie z. B. die letzte Aktion
Strich für eine Zeichen-App für einen bestimmten Zeiger.
AKTION_ABBRECHEN
In Android 1.0 (API-Level 1) hinzugefügt
ACTION_CANCEL
gibt an, dass der vorherige Satz von Bewegungsereignissen abgebrochen werden soll.
ACTION_CANCEL
wird ausgelöst, wenn eines der folgenden Elemente erkannt wird:
- Touch-Gesten für die Navigation
- Ablehnung der Handfläche
Wenn ACTION_CANCEL
ausgelöst wird, sollten Sie den aktiven Cursor mit
getPointerId(getActionIndex())
. Entfernen Sie dann den mit diesem Zeiger erstellten Strich aus dem Eingabeverlauf und rendern Sie die Szene erneut.
FLAG_ABGEBROCHEN
In Android 13 (API-Level 33) hinzugefügt
FLAG_CANCELED
zeigt an, dass der nach oben gerichtete Zeiger eine unbeabsichtigte Berührung durch den Nutzer war. Die Kennzeichnung lautet
wird in der Regel festgelegt, wenn der Nutzer versehentlich den Bildschirm berührt, z. B. durch
Gerät oder legen Sie die Handfläche auf den Bildschirm.
So greifen Sie auf den Flag-Wert zu:
val cancel = (event.flags and FLAG_CANCELED) == FLAG_CANCELED
Wenn das Flag gesetzt ist, müssen Sie die letzte MotionEvent
-Einstellung rückgängig machen, also
ACTION_DOWN
von diesem Punkt entfernt.
Wie ACTION_CANCEL
kann der Zeiger mit getPointerId(actionIndex)
gefunden werden.
Vollbild-, Rand-zu-Rand- und Navigationsgesten
Wenn eine App im Vollbildmodus zu sehen ist und am Rand praktisch nutzbare Elemente wie das einer Zeichen- oder Notiz-App, indem Sie vom unteren Bildschirmrand Navigation anzeigen oder die App in den Hintergrund verschieben, kann dies zu einer unbeabsichtigte Berührungen.
<ph type="x-smartling-placeholder">Um zu verhindern, dass Gesten unerwünschte Berührungen in Ihrer App auslösen, können Sie
Insets und
ACTION_CANCEL
Weitere Informationen finden Sie im Hilfeartikel Palmenablehnung, Navigation und unerwünschte Eingaben. .
Verwenden Sie die Methode
setSystemBarsBehavior()
und
BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
von
WindowInsetsController
So verhindern Sie, dass Navigationsgesten unerwünschte Touch-Ereignisse verursachen:
// Configure the behavior of the hidden system bars.
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
Weitere Informationen zur Verwaltung von Einfügungen und Touch-Gesten finden Sie unter:
- Systemleisten für immersiven Modus ausblenden
- Kompatibilität mit der Bedienung über Gesten gewährleisten
- Edge-to-Edge-Inhalte in der App präsentieren
Niedrige Latenz
Die Latenz ist die Zeit, die Hardware, System und Anwendung für die Verarbeitung benötigen und rendern Nutzereingaben.
Latenz = Eingabeverarbeitung von Hardware und Betriebssystem + App-Verarbeitung + Zusammensetzung des Systems
- Hardware-Rendering
Quelle der Latenz
- Eingabestift auf Touchscreen registrieren (Hardware): Erste kabellose Verbindung wenn Eingabestift und Betriebssystem kommunizieren, um registriert und synchronisiert zu werden.
- Rate der Touch Sampling (Hardware): Häufigkeit, mit der ein Touchscreen pro Sekunde auf einem Touchscreen wiedergegeben wird Prüft, ob ein Zeiger die Oberfläche berührt. Die Bandbreite liegt zwischen 60 und 1.000 Hz.
- Eingabeverarbeitung (App): Farben, grafische Effekte und Transformation anwenden auf Nutzereingaben.
- Grafikrendering (Betriebssystem und Hardware): Pufferaustausch, Hardwareverarbeitung
Grafik mit niedriger Latenz
Jetpack-Grafikbibliothek mit niedriger Latenz verkürzt die Verarbeitungszeit zwischen Nutzereingabe und Bildschirmrendering.
Die Bibliothek reduziert die Verarbeitungszeit, indem sie Multi-Zwischenspeicher-Rendering und eine Frontpuffer-Rendering-Technik, bei der direkt in auf dem Bildschirm.
Frontbuffer-Rendering
Der Front-Zwischenspeicher ist der Arbeitsspeicher, den der Bildschirm für das Rendern verwendet. Es ist am nächsten Apps direkt auf dem Bildschirm zu zeichnen. Die Low-Latenz-Bibliothek ermöglicht direkt im Front-Puffer zu rendern. Dadurch wird die Leistung verbessert, Zwischenspeichern wird verhindert, wie es beim herkömmlichen Rendering mit mehreren Zwischenspeichern häufig der Fall ist. oder mit doppeltem Zwischenspeichern (am häufigsten) ausgeführt werden.
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">Auch wenn das Frontpuffer-Rendering eine großartige Technik ist, um einen kleinen Bereich des Bildschirm ist, ist sie nicht für die Aktualisierung des gesamten Bildschirms gedacht. Mit Frontbuffer-Rendering, rendert die App Inhalte in einem Puffer, aus dem was der Bildschirm anzeigt. Daher besteht die Möglichkeit, dass Artefakte verursacht oder reißen (siehe unten).
Die Bibliothek mit niedriger Latenz ist ab Android 10 (API-Level 29) verfügbar sowie auf ChromeOS-Geräten mit Android 10 (API-Level 29) und höher.
Abhängigkeiten
Die Bibliothek mit niedriger Latenz stellt die Komponenten für das Frontbuffer-Rendering bereit
Implementierung. Die Bibliothek wird als Abhängigkeit im Modul der Anwendung hinzugefügt.
build.gradle
-Datei:
dependencies {
implementation "androidx.graphics:graphics-core:1.0.0-alpha03"
}
GLFrontBufferRenderer-Callbacks
Die Low-Latenz-Bibliothek enthält
GLFrontBufferRenderer.Callback
Interface, das die folgenden Methoden definiert:
Die Bibliothek mit niedriger Latenz hat keine Meinung hinsichtlich der Art der Daten, die Sie mit
GLFrontBufferRenderer
Die Bibliothek verarbeitet die Daten jedoch als Strom von Hunderten von Datenpunkten. und so gestalten Sie Ihre Daten so, dass die Speichernutzung und -zuweisung optimiert ist.
Rückrufe
Implementieren Sie GLFrontBufferedRenderer.Callback
und
onDrawFrontBufferedLayer()
und onDrawDoubleBufferedLayer()
überschreiben.
GLFrontBufferedRenderer
verwendet die Callbacks, um deine Daten so gut wie möglich zu rendern
optimal nutzen können.
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.
}
}
Instanz von GLFrontBufferedRenderer deklarieren
Bereiten Sie die GLFrontBufferedRenderer
vor, indem Sie die SurfaceView
und
die Sie zuvor erstellt haben. GLFrontBufferedRenderer
optimiert das Rendering
in den vorderen und doppelten Puffer ein, indem Sie Ihre Callbacks verwenden:
var glFrontBufferRenderer = GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks)
Rendering
Das Front-Puffer-Rendering beginnt, wenn Sie die
renderFrontBufferedLayer()
, die den onDrawFrontBufferedLayer()
-Callback auslöst.
Das Rendering mit doppelter Zwischenspeicherung wird fortgesetzt, wenn Sie die Methode
commit()
, die den onDrawMultiDoubleBufferedLayer()
-Callback auslöst.
Im folgenden Beispiel rendert der Prozess im Front-Zwischenspeicher (schnelle
Rendern), wenn der Nutzer mit dem Zeichnen auf dem Bildschirm beginnt (ACTION_DOWN
) und sich
den Zeiger um (ACTION_MOVE
). Der Prozess wird im doppelten Zwischenspeicher gerendert.
wenn der Zeiger die Bildschirmoberfläche verlässt (ACTION_UP
).
Sie können
requestUnbufferedDispatch()
dass das Eingabesystem keine Bewegungsereignisse bündelt, sondern
sobald sie verfügbar sind:
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()
}
}
Tipps zum Rendern
Kleine Bildschirmbereiche, Handschrift, Zeichnen, Skizzieren
Vollbildaktualisierung, Schwenken, Zoomen. Dies kann zum Zerreißen führen.
Reißend
Zerreißen entsteht, wenn der Bildschirm aktualisiert wird, während der Bildschirmzwischenspeicher läuft. geändert werden. Ein Teil des Bildschirms zeigt neue Daten, ein anderer werden alte Daten angezeigt.
<ph type="x-smartling-placeholder">Bewegungsvorhersage
Die Jetpack-Bewegungsvorhersage Bibliothek reduziert empfundene Latenz, indem der Schlagpfad des Nutzers geschätzt und temporäre, auf den Renderer verweist.
Die Bibliothek für Bewegungsvorhersagen erhält echte Nutzereingaben als MotionEvent
-Objekte.
Die Objekte enthalten Informationen über x- und y-Koordinaten, Druck und Zeit
die vom Bewegungsvorhersager genutzt werden, um zukünftige MotionEvent
-Werte vorherzusagen.
Objekte.
Vorhergesagte MotionEvent
-Objekte sind nur Schätzungen. Die Zahl der vorhergesagten Ereignisse kann
wahrgenommene Latenz, aber vorhergesagte Daten müssen durch die tatsächlichen MotionEvent
ersetzt werden
sobald sie empfangen wurden.
Die Bibliothek für Bewegungsvorhersagen ist ab Android 4.4 (API-Level 19) und und auf ChromeOS-Geräten mit Android 9 (API-Level 28) und höher.
<ph type="x-smartling-placeholder">Abhängigkeiten
Die Bibliothek für die Bewegungsvorhersage implementiert die Vorhersagefunktionen. Die
-Bibliothek wird als Abhängigkeit in der Moduldatei build.gradle
der App hinzugefügt:
dependencies {
implementation "androidx.input:input-motionprediction:1.0.0-beta01"
}
Implementierung
Die Bibliothek für Bewegungsvorhersagen enthält
MotionEventPredictor
Interface, das die folgenden Methoden definiert:
record()
: SpeichertMotionEvent
-Objekte als Datensatz der Nutzeraktionenpredict()
: Gibt eine vorhergesagteMotionEvent
zurück
Instanz von MotionEventPredictor
deklarieren
var motionEventPredictor = MotionEventPredictor.newInstance(view)
Den Predictor mit Daten versorgen
motionEventPredictor.record(motionEvent)
Vorhersage
when (motionEvent.action) {
MotionEvent.ACTION_MOVE -> {
val predictedMotionEvent = motionEventPredictor?.predict()
if(predictedMotionEvent != null) {
// use predicted MotionEvent to inject a new artificial point
}
}
}
Tipps zur Bewegungsvorhersage
Entfernen Sie Vorhersagepunkte, wenn ein neuer vorhergesagter Punkt hinzugefügt wird.
Verwenden Sie für das endgültige Rendering keine Vorhersagepunkte.
Notizen-Apps
Über ChromeOS können in deiner App bestimmte Aktionen zum Erstellen von Notizen deklariert werden.
Informationen dazu, wie Sie eine App als Notizen-App unter ChromeOS registrieren, finden Sie unter Eingabe Kompatibilität.
Informationen dazu, wie Sie eine App auf Android-Geräten für Notizen registrieren, finden Sie unter Notizen erstellen App.
Mit Android 14 (API-Level 34) wurde die
ACTION_CREATE_NOTE
Intent, mit dem deine App eine Notizaktivität für das Schloss starten kann
Bildschirm.
Digitale Tintenerkennung mit ML Kit
Mit der digitalen Tinte des ML Kits Erkennung, erkennt Ihre App handschriftlichen Text auf einer digitalen Oberfläche in Hunderten von Sprachen. Sie können auch Skizzen klassifizieren.
ML Kit bietet die
Ink.Stroke.Builder
Klasse Ink
-Objekte, die von Modellen für maschinelles Lernen verarbeitet werden können.
um Handschrift in Text umzuwandeln.
Neben der Handschrifterkennung kann das Modell Gesten, wie „Löschen“ und „Einkreisen“.
Weitere Informationen finden Sie unter Digitale Tinte Erkennung um mehr zu erfahren.