Eingabekompatibilität auf großen Bildschirmen

Auf Geräten mit großem Bildschirm interagieren Nutzer häufig mit Apps über eine Tastatur, Maus, ein Touchpad, einen Eingabestift oder ein Gamepad. So aktivieren Sie, dass Ihre App Eingaben von externen Geräten akzeptiert:

  • Testen Sie die grundlegende Tastaturunterstützung, z. B. Strg + Z zum Rückgängigmachen, Strg + C zum Kopieren und Strg + S zum Speichern. Eine Liste der standardmäßigen Tastenkombinationen finden Sie unter Tastaturaktionen verarbeiten.
  • Testen Sie die erweiterte Tastaturunterstützung, z. B. die Navigation per Tabulatortaste und Pfeiltasten, die Bestätigung der Texteingabe per Eingabetaste und die Wiedergabe und Pause in Medien-Apps per Leertaste.
  • Testen Sie grundlegende Mausinteraktionen, einschließlich Rechtsklicks für das Kontextmenü, Symboländerungen beim Bewegen des Mauszeigers und Mausrad- oder Touchpad-Scrollereignisse für benutzerdefinierte Komponenten.
  • App-spezifische Eingabegeräte testen, z. B. Eingabestifte, Gamecontroller und MIDI-Controller für Musik-Apps
  • Berücksichtigen Sie erweiterte Eingabemethoden, mit denen sich Ihre App in Desktopumgebungen abheben kann, z. B. ein Touchpad als Cross-Fader für DJ-Apps, die Mauserfassung für Spiele und Tastenkürzel für Nutzer, die hauptsächlich die Tastatur verwenden.

Tastatur

Die Art und Weise, wie Ihre App auf die Tastatureingabe reagiert, trägt zur Nutzerfreundlichkeit auf dem großen Bildschirm bei. Es gibt drei Arten von Tastatureingaben: Navigation, Tastenanschlag und Tastenkürzel.

Die Tastaturnavigation wird in Touch-orientierten Apps selten implementiert, aber Nutzer erwarten sie, wenn sie eine App verwenden und eine Tastatur zur Hand haben. Die Tastaturnavigation kann für Nutzer mit Beeinträchtigungen auf Smartphones, Tablets, faltbaren Geräten und Computern unerlässlich sein.

Bei vielen Apps wird die Navigation mit den Pfeiltasten und der Tabulatortaste automatisch vom Android-Framework verarbeitet. Einige Elemente können beispielsweise standardmäßig fokussiert werden, z. B. Button oder ein Element mit dem Modifikator clickable. Die Tastaturnavigation sollte in der Regel ohne zusätzlichen Code funktionieren. Wenn Sie die Tastaturnavigation für benutzerdefinierte Composeables aktivieren möchten, die standardmäßig nicht fokussierbar sind, fügen Sie den Modifikator focusable hinzu:

var color by remember { mutableStateOf(Green) }
Box(
    Modifier
        .background(color)
        .onFocusChanged { color = if (it.isFocused) Blue else Green }
        .focusable()
) {
    Text("Focusable 1")
}

Weitere Informationen finden Sie unter Kompositelemente fokussierbar machen.

Wenn der Fokus aktiviert ist, erstellt das Android-Framework eine Navigationszuordnung für alle fokussierbaren Komponenten basierend auf ihrer Position. Das funktioniert in der Regel wie erwartet und es sind keine weiteren Entwicklungen erforderlich.

Bei komplexen Compose-Elementen wie Tabs und Listen wird jedoch nicht immer das richtige nächste Element für die Tabnavigation bestimmt. Das ist beispielsweise der Fall, wenn eines der Compose-Elemente horizontal scrollbar ist und nicht vollständig sichtbar ist.

Wenn Sie das Fokusverhalten steuern möchten, fügen Sie dem übergeordneten Composeable einer Sammlung von Composeables den Modifikator focusGroup hinzu. Der Fokus bewegt sich auf die Gruppe und dann durch die Gruppe, bevor er zur nächsten fokussierbaren Komponente wechselt, z. B.:

Row {
    Column(Modifier.focusGroup()) {
        Button({}) { Text("Row1 Col1") }
        Button({}) { Text("Row2 Col1") }
        Button({}) { Text("Row3 Col1") }
    }
    Column(Modifier.focusGroup()) {
        Button({}) { Text("Row1 Col2") }
        Button({}) { Text("Row2 Col2") }
        Button({}) { Text("Row3 Col2") }
    }
}

Weitere Informationen finden Sie unter Mithilfe von Fokusgruppen für eine einheitliche Navigation sorgen.

Testen Sie den Zugriff auf alle UI-Elemente Ihrer App nur mit der Tastatur. Häufig verwendete Elemente sollten ohne Maus oder Touchbedienung zugänglich sein.

Denken Sie daran, dass die Tastaturunterstützung für Nutzer mit Beeinträchtigungen möglicherweise unerlässlich ist.

Tastenanschläge

Bei der Texteingabe, die von einer virtuellen Bildschirmtastatur (IME) verarbeitet wird, z. B. fürTextField, sollten Apps auf Geräten mit großem Display ohne zusätzliche Entwicklungsarbeit wie erwartet funktionieren. Bei Tastendrücken, die vom Framework nicht vorhergesehen werden können, müssen Apps das Verhalten selbst steuern. Das gilt insbesondere für Apps mit benutzerdefinierten Ansichten.

Beispiele hierfür sind Chat-Apps, in denen mit der Eingabetaste eine Nachricht gesendet wird, Medien-Apps, in denen die Wiedergabe mit der Leertaste gestartet und angehalten wird, und Spiele, in denen die Bewegung mit den Tasten w, a, s und d gesteuert wird.

Mit dem Modifikator onKeyEvent können Sie einzelne Tastenanschläge verarbeiten. Er akzeptiert ein Lambda, das aufgerufen wird, wenn die geänderte Komponente ein Tastenereignis empfängt. Mit der Property KeyEvent#type können Sie feststellen, ob es sich bei dem Ereignis um eine Tastendruck- (KeyDown) oder eine Tastenrelease-Ereignis (KeyUp) handelt:

Box(
    modifier = Modifier.focusable().onKeyEvent {
        if(
            it.type == KeyEventType.KeyUp &&
            it.key == Key.S
        ) {
            doSomething()
            true
        } else {
            false
        }
    }
)  {
    Text("Press S key")
}

Alternativ kannst du den Rückruf onKeyUp() überschreiben und das erwartete Verhalten für jeden empfangenen Schlüsselcode hinzufügen:

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
    return when (keyCode) {
        KeyEvent.KEYCODE_ENTER -> {
            sendChatMessage()
            true
        }
        KeyEvent.KEYCODE_SPACE -> {
            playOrPauseMedia()
            true
        }
        else -> super.onKeyUp(keyCode, event)
    }
}

Ein onKeyUp-Ereignis tritt auf, wenn eine Taste losgelassen wird. Wenn Sie den Rückruf verwenden, müssen Apps nicht mehrere onKeyDown-Ereignisse verarbeiten, wenn eine Taste gedrückt gehalten oder langsam losgelassen wird. Spiele und Apps, die erkennen müssen, wann eine Taste gedrückt wird oder ob der Nutzer eine Taste gedrückt hält, können auf das onKeyDown-Ereignis warten und wiederholte onKeyDown-Ereignisse selbst verarbeiten.

Weitere Informationen finden Sie unter Tastaturaktionen verarbeiten.

Verknüpfungen

Gängige Tastenkombinationen, die die Tasten Strg, Alt, Umschalt und Meta enthalten, sind bei der Verwendung einer Hardwaretastatur zu erwarten. Wenn eine App keine Tastenkürzel implementiert, kann das für Nutzer frustrierend sein. Fortgeschrittene Nutzer schätzen auch Tastenkürzel für häufig verwendete appspezifische Aufgaben. Mithilfe von Tastenkürzeln lässt sich die Bedienung einer App vereinfachen und sie unterscheidet sich von Apps ohne Tastenkürzel.

Zu den gängigen Tastenkombinationen gehören Strg + S (speichern), Strg + Z (rückgängig machen) und Strg + Umschalt + Z (wiederholen). Eine Liste der Standard-Tastenkürzel finden Sie unter Tastaturaktionen verarbeiten.

Ein KeyEvent-Objekt hat die folgenden Attribute, die angeben, ob Modifikatortasten gedrückt werden:

Beispiel:

Box(
    Modifier.onKeyEvent {
        if (it.isAltPressed && it.key == Key.A) {
            println("Alt + A is pressed")
            true
        } else {
            false
        }
    }
    .focusable()
)

Weitere Informationen finden Sie hier:

Eingabestift

Viele Geräte mit großem Display werden mit einem Eingabestift geliefert. Android-Apps behandeln Eingabestifte als Eingabe über den Touchscreen. Einige Geräte haben möglicherweise auch ein USB- oder Bluetooth-Zeichentablet, z. B. das Wacom Intuos. Android-Apps können Bluetooth-Eingabe, aber keine USB-Eingabe empfangen.

Wenn Sie auf Objekte des Eingabestifts MotionEvent zugreifen möchten, fügen Sie der Zeichenfläche den Modifikator pointerInteropFilter hinzu. Implementieren Sie eine ViewModel-Klasse mit einer Methode, die Bewegungsereignisse verarbeitet. Übergeben Sie die Methode als onTouchEvent-Lambda des pointerInteropFilter-Modifikators:

@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun DrawArea(modifier: Modifier = Modifier) {
   Canvas(modifier = modifier
       .clipToBounds()
       .pointerInteropFilter {
           viewModel.processMotionEvent(it)
       }

   ) {
       // Drawing code here.
   }
}

Das MotionEvent-Objekt enthält Informationen zum Ereignis:

Bisherige Punkte

Android fasst Eingabeereignisse in Batches zusammen und sendet sie einmal pro Frame. Ein Eingabestift kann Ereignisse viel häufiger als das Display melden. Wenn Sie Zeichen-Apps erstellen, können Sie mithilfe der getHistorical APIs nach Ereignissen in der jüngeren Vergangenheit suchen:

Ablehnung der Hand

Wenn Nutzer mit einem Eingabestift zeichnen, schreiben oder mit Ihrer App interagieren, berühren sie manchmal den Bildschirm mit der Handfläche. Das Touch-Ereignis (auf ACTION_DOWN oder ACTION_POINTER_DOWN festgelegt) kann an Ihre App gemeldet werden, bevor das System die unbeabsichtigte Berührung mit der Handfläche erkennt und ignoriert.

Android sendet ein MotionEvent, um Palm-Touch-Ereignisse abzubrechen. Wenn Ihre App ACTION_CANCEL empfängt, brechen Sie die Geste ab. Wenn Ihre App ACTION_POINTER_UP empfängt, prüfen Sie, ob FLAG_CANCELED festgelegt ist. Falls ja, brechen Sie die Geste ab.

Prüfen Sie nicht nur FLAG_CANCELED. Unter Android 13 (API-Level 33) und höher setzt das System FLAG_CANCELED für ACTION_CANCEL-Ereignisse. Unter niedrigeren Android-Versionen wird das Flag jedoch nicht gesetzt.

Android 12

Unter Android 12 (API-Level 32) und niedriger ist die Erkennung der Handflächenabwehr nur für Touch-Ereignisse mit einem einzelnen Touch-Punkt möglich. Wenn ein Touch mit der Handfläche der einzige Zeiger ist, bricht das System das Ereignis ab, indem es ACTION_CANCEL auf das Bewegungsereignisobjekt setzt. Wenn andere Touchstifte nicht aktiv sind, setzt das System ACTION_POINTER_UP. Das ist nicht ausreichend, um die Ablehnung der Handerkennung zu erkennen.

Android 13

Unter Android 13 (API-Level 33) und höher bricht das System das Ereignis ab, wenn ein Touch mit der Handfläche der einzige Zeiger ist, indem es ACTION_CANCEL und FLAG_CANCELED für das Bewegungsereignisobjekt festlegt. Wenn andere Zeiger unten sind, setzt das System ACTION_POINTER_UP und FLAG_CANCELED.

Wenn Ihre App ein Bewegungsereignis mit ACTION_POINTER_UP empfängt, prüfen Sie, ob FLAG_CANCELED vorhanden ist, um festzustellen, ob das Ereignis auf eine Ablehnung der Handfläche oder eine andere Ereignisannullierung hinweist.

Notizen-Apps

ChromeOS hat eine spezielle Intent-Funktion, mit der registrierte Notizen-Apps für Nutzer angezeigt werden. Wenn Sie eine App als Notiz-App registrieren möchten, fügen Sie Ihrem App-Manifest Folgendes hinzu:

<intent-filter>
    <action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

Wenn eine App beim System registriert ist, kann der Nutzer sie als Standard-App zum Erstellen von Notizen auswählen. Wenn eine neue Notiz angefordert wird, sollte die App eine leere Notiz erstellen, die für die Eingabe per Eingabestift bereit ist. Wenn der Nutzer ein Bild (z. B. einen Screenshot oder ein heruntergeladenes Bild) mit Anmerkungen versehen möchte, wird die App mit ClipData gestartet, die ein oder mehrere Elemente mit content://-URIs enthält. Die App sollte eine Notiz erstellen, bei der das erste angehängte Bild als Hintergrundbild verwendet wird, und in einen Modus wechseln, in dem der Nutzer mit einem Eingabestift auf dem Display zeichnen kann.

Absichten zum Erstellen von Notizen ohne Eingabestift testen

[TBD remove section.]

Wenn Sie testen möchten, ob eine App ohne aktiven Eingabestift richtig auf Notizen-Intents reagiert, können Sie die Notizenoptionen auf ChromeOS so anzeigen:

  1. In den Entwicklermodus wechseln und das Gerät beschreibbar machen
  2. Drücken Sie Strg + Alt + F2, um ein Terminal zu öffnen.
  3. Führen Sie den Befehl sudo vi /etc/chrome_dev.conf aus.
  4. Drücken Sie die Taste i, um die Datei zu bearbeiten und --ash-enable-palette in eine neue Zeile am Ende der Datei einzufügen.
  5. Speichern Sie die Datei, indem Sie die Esc-Taste drücken und dann :, w, q und die Eingabetaste drücken.
  6. Drücken Sie Strg + Alt + F1, um zur normalen ChromeOS-Benutzeroberfläche zurückzukehren.
  7. Melden Sie sich ab und dann wieder an.

Im Bereich „Zubehör“ sollte jetzt ein Menü für Eingabestifte angezeigt werden:

  • Tippen Sie im Bereich „Favoriten“ auf die Stifttaste und wählen Sie Neue Notiz aus. Daraufhin sollte eine leere Notiz geöffnet werden.
  • Machen Sie einen Screenshot. Wählen Sie im Bereich „Steuerfeld“ die Schaltfläche für den Eingabestift > Bildschirm erfassen aus oder laden Sie ein Bild herunter. In der Benachrichtigung sollte die Option Bild annotieren angezeigt werden. Dadurch wird die App gestartet und das Bild kann mit Anmerkungen versehen werden.

Unterstützung für Maus und Touchpad

Die meisten Apps müssen in der Regel nur drei Ereignisse für große Bildschirme verarbeiten: Rechtsklick, Bewegung des Mauszeigers und Ziehen und Droppen.

Rechtsklick

Alle Aktionen, die dazu führen, dass in einer App ein Kontextmenü angezeigt wird, z. B. das Berühren und Halten eines Listenelements, sollten auch auf Rechtsklicke reagieren.

Um Rechtsklick-Ereignisse zu verarbeiten, sollten Apps einen View.OnContextClickListener registrieren:

Box(modifier = Modifier.fillMaxSize()) {
    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { context ->
            val rootView = FrameLayout(context)
            val onContextClickListener =
                View.OnContextClickListener { view ->
                    showContextMenu()
                    true
                }
            rootView.setOnContextClickListener(onContextClickListener)
            rootView
        },
    )
}

Weitere Informationen zum Erstellen von Kontextmenüs finden Sie unter Kontextmenü erstellen.

Mauszeiger hierher bewegen

Mit Hover-Ereignissen können Sie Ihre App-Layouts ansprechender und nutzerfreundlicher gestalten. Das gilt besonders für benutzerdefinierte-Komponenten:

Die beiden häufigsten Beispiele hierfür sind:

  • Nutzer durch Ändern des Mauszeigersymbols darauf hinweisen, ob ein Element interaktiv ist, z. B. anklickbar oder bearbeitbar
  • Visuelles Feedback für Elemente in einer großen Liste oder einem großen Raster hinzufügen, wenn der Mauszeiger darauf bewegt wird

Drag-and-Drop

In einer Umgebung mit mehreren Fenstern erwarten Nutzer, dass sie Elemente per Drag-and-drop zwischen Apps verschieben können. Das gilt für Computer sowie für Tablets, Smartphones und faltbare Geräte im Splitscreen-Modus.

Überlegen Sie, ob Nutzer wahrscheinlich Elemente in Ihre App ziehen werden. Beispielsweise sollten Bildeditoren Fotos, Audioplayer Audiodateien und Zeichenprogramme Fotos empfangen können.

Informationen zum Hinzufügen der Drag-and-drop-Unterstützung finden Sie unter Drag-and-drop sowie im Blogpost Android on ChromeOS – Implementing Drag & Drop.

Besondere Hinweise für ChromeOS

Erweiterte Unterstützung für den Cursor

Apps, die die Maus- und Touchpad-Eingabe erweitert verarbeiten, sollten einen-Modifikator mit pointerInput implementieren, um eine PointerEvent zu erhalten:

@Composable
private fun LogPointerEvents(filter: PointerEventType? = null) {
    var log by remember { mutableStateOf("") }
    Column {
        Text(log)
        Box(
            Modifier
                .size(100.dp)
                .background(Color.Red)
                .pointerInput(filter) {
                    awaitPointerEventScope {
                        while (true) {
                            val event = awaitPointerEvent()
                            // handle pointer event
                            if (filter == null || event.type == filter) {
                                log = "${event.type}, ${event.changes.first().position}"
                            }
                        }
                    }
                }
        )
    }
}

Prüfen Sie das PointerEvent-Objekt, um Folgendes zu ermitteln:

Controller

Einige Android-Geräte mit großem Display unterstützen bis zu vier Gamecontroller. Verwenden Sie die standardmäßigen Android-Gamecontroller-APIs, um Gamecontroller zu steuern (siehe Gamecontroller unterstützen).

Die Tasten des Gamepads werden gemäß einer gängigen Zuordnung gängigen Werten zugeordnet. Allerdings folgen nicht alle Gamecontroller-Hersteller denselben Zuordnungskonventionen. Sie können die Nutzerfreundlichkeit erheblich verbessern, wenn Sie Nutzern die Auswahl verschiedener gängiger Controller-Belegungen ermöglichen. Weitere Informationen finden Sie unter Gamepad-Tastendrücke verarbeiten.

Übersetzungsmodus für die Eingabe

In ChromeOS ist standardmäßig ein Eingabeübersetzungsmodus aktiviert. Bei den meisten Android-Apps sorgt dieser Modus dafür, dass Apps in einer Desktopumgebung wie erwartet funktionieren. Beispiele hierfür sind das automatische Aktivieren des Zwei-Finger-Scrollens auf dem Touchpad, das Scrollen mit dem Mausrad und das Zuordnen von Rohdisplaykoordinaten zu Fensterkoordinaten. Im Allgemeinen müssen App-Entwickler diese Funktionen nicht selbst implementieren.

Wenn eine App ein benutzerdefiniertes Eingabeverhalten implementiert, z. B. eine benutzerdefinierte Touchpad-Pinch-Aktion mit zwei Fingern, oder diese Eingabeübersetzungen nicht die von der App erwarteten Eingabeereignisse liefern, können Sie den Modus für die Eingabeübersetzung deaktivieren, indem Sie dem Android-Manifest das folgende Tag hinzufügen:

<uses-feature
    android:name="android.hardware.type.pc"
    android:required="false" />

Weitere Informationen