Bedienung über Gesten und randlose Bedienung

1. Einführung

Unter Android 10 oder höher werden Navigationsgesten als neuer Modus unterstützt. So kann Ihre App den gesamten Bildschirm nutzen und ein noch intensiveres Anzeigeerlebnis bieten. Wenn der Nutzer vom unteren Displayrand nach oben wischt, wird er zum Android-Startbildschirm weitergeleitet. Wenn der Nutzer vom linken oder rechten Rand nach innen wischt, wird der vorherige Bildschirm angezeigt.

Mit diesen beiden Gesten kann Ihre App den unteren Bereich des Displays nutzen. Wenn Ihre App jedoch Gesten verwendet oder Steuerelemente in den Bereichen für Systemgesten hat, kann es zu Konflikten mit systemweiten Gesten kommen.

In diesem Codelab erfahren Sie, wie Sie Insets verwenden, um Konflikte mit Gesten zu vermeiden. Außerdem soll in diesem Codelab gezeigt werden, wie Sie die Gesture Exclusion API für Steuerelemente wie Ziehpunkte verwenden, die sich in den Gestenzonen befinden müssen.

Lerninhalte

  • Inset-Listener für Ansichten verwenden
  • Gesture Exclusion API verwenden
  • Verhalten des immersiven Modus bei aktiven Gesten

In diesem Codelab erfahren Sie, wie Sie Ihre App mit Systemgesten kompatibel machen. Irrelevante Konzepte und Codeblöcke werden nicht beachtet und können einfach kopiert und eingefügt werden.

Umfang

Der Universal Android Music Player (UAMP) ist eine Beispiel-Musikplayer-App für Android, die in Kotlin geschrieben wurde. Sie richten UAMP für die Bedienung über Gesten ein.

  • Steuerelemente mit Insets von Gestenbereichen entfernen
  • Mit der Gesture Exclusion API die Zurück-Geste für Steuerelemente deaktivieren, die in Konflikt stehen
  • Mit Ihren Builds Verhaltensänderungen im Immersivmodus mit der Gestensteuerung untersuchen

Voraussetzungen

2. App-Übersicht

Der Universal Android Music Player (UAMP) ist eine Beispiel-App für einen Musikplayer für Android, die in Kotlin geschrieben wurde. Es unterstützt Funktionen wie die Hintergrundwiedergabe, die Verarbeitung des Audiofokus, die Assistant-Integration und mehrere Plattformen wie Wear, TV und Auto.

Abbildung 1: Ein Ablauf in UAMP

UAMP lädt einen Musikkatalog von einem Remote-Server und ermöglicht es dem Nutzer, die Alben und Titel zu durchsuchen. Der Nutzer tippt auf einen Song und er wird über verbundene Lautsprecher oder Kopfhörer wiedergegeben. Die App ist nicht für die Verwendung mit Systemgesten konzipiert. Wenn Sie UAMP auf einem Gerät mit Android 10 oder höher ausführen, treten daher anfangs einige Probleme auf.

3. Einrichten

Wenn Sie die Beispielanwendung herunterladen möchten, klonen Sie das Repository von GitHub und wechseln Sie zum Zweig starter:

$  git clone https://github.com/googlecodelabs/android-gestural-navigation/

Alternativ können Sie das Repository als ZIP-Datei herunterladen, entzippen und in Android Studio öffnen.

Gehen Sie folgendermaßen vor:

  1. Öffnen Sie die App in Android Studio und erstellen Sie sie.
  2. Erstellen Sie ein neues virtuelles Gerät und wählen Sie API-Level 29 aus. Alternativ können Sie ein echtes Gerät mit API-Level 29 oder höher anschließen.
  3. Führen Sie die App aus. In der Liste, die angezeigt wird, werden die Songs unter den Optionen Empfohlen und Alben gruppiert.
  4. Klicke auf Empfohlen und wähle einen Song aus der Liste aus.
  5. Die App beginnt mit der Wiedergabe des Songs.

Bedienung über Gesten aktivieren

Wenn Sie eine neue Emulatorinstanz mit API-Level 29 ausführen, ist die Gestensteuerung möglicherweise nicht standardmäßig aktiviert. Wenn Sie die Bedienung über Gesten aktivieren möchten, wählen Sie Systemeinstellungen > System > Systemsteuerung > Bedienung über Gesten aus.

App mit der Bedienung über Gesten ausführen

Wenn Sie die App mit aktivierter Bewegungssteuerung ausführen und die Wiedergabe eines Songs starten, befinden sich die Player-Steuerelemente möglicherweise sehr nah an den Bereichen für die Startbildschirm- und Zurück-Gesten.

4. Edge-to-Edge-Anzeige

Was bedeutet „Edge-to-Edge“?

Apps, die unter Android 10 oder höher ausgeführt werden, können unabhängig davon, ob für die Navigation Gesten oder Schaltflächen aktiviert sind, auf dem gesamten Bildschirm angezeigt werden. Damit Ihre Apps ein Edge-to-Edge-Erlebnis bieten, müssen sie hinter der transparenten Navigations- und Statusleiste gerendert werden.

Hinter der Navigationsleiste zeichnen

Damit in Ihrer App Inhalte unter der Navigationsleiste gerendert werden können, müssen Sie zuerst den Hintergrund der Navigationsleiste transparent machen. Dann müssen Sie die Statusleiste transparent machen. So kann Ihre App über die gesamte Höhe des Bildschirms angezeigt werden.

So ändern Sie die Farbe der Navigationsleiste und der Statusleiste:

  1. Navigationsleiste:Öffnen Sie res/values-29/styles.xml und legen Sie für navigationBarColor den Wert color/transparent fest.
  2. Statusleiste:Setzen Sie statusBarColor auf color/transparent.

Sehen Sie sich das folgende Codebeispiel für res/values-29/styles.xml an:

<!-- change navigation bar color -->
<item name="android:navigationBarColor">
    @android:color/transparent
</item>

<!-- change status bar color -->
<item name="android:statusBarColor">
    @android:color/transparent
</item>

Sichtbarkeits-Flags für die System-UI

Außerdem müssen Sie die Sichtbarkeits-Flags der System-UI festlegen, damit das System die App unter den Systemleisten anordnet. Mit den systemUiVisibility-APIs in der Klasse View lassen sich verschiedene Flags festlegen. Führen Sie diese Schritte aus:

  1. Öffnen Sie die Klasse MainActivity.kt und suchen Sie die Methode onCreate(). Rufen Sie eine Instanz von fragmentContainer ab.
  2. Setzen Sie Folgendes auf content.systemUiVisibility:

Sehen Sie sich das folgende Codebeispiel für MainActivity.kt an:

  val content: FrameLayout = findViewById(R.id.fragmentContainer)
  content.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
            View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

Wenn Sie diese Flags zusammen festlegen, teilen Sie dem System mit, dass Ihre App im Vollbildmodus angezeigt werden soll, als wären die Navigations- und Statusleisten nicht vorhanden. Führen Sie diese Schritte aus:

  1. Starte die App und wähle einen Titel aus, um zum Player-Bildschirm zu gelangen.
  2. Prüfe, ob die Player-Steuerelemente unter der Navigationsleiste angezeigt werden und daher schwer zugänglich sind:

  1. Gehen Sie zu den Systemeinstellungen, wechseln Sie zurück zum Navigationsmodus mit drei Schaltflächen und kehren Sie zur App zurück.
  2. Prüfen Sie, ob die Steuerelemente mit der Navigationsleiste mit drei Schaltflächen noch schwieriger zu verwenden sind: Das SeekBar ist hinter der Navigationsleiste verborgen und Wiedergabe/Pause wird größtenteils von der Navigationsleiste verdeckt.
  3. Probieren Sie ein bisschen herum. Kehren Sie anschließend zu den Systemeinstellungen zurück und stellen Sie wieder auf „Bedienung über Gesten“ um:

741ef664e9be5e7f.gif

Die App wird jetzt randlos dargestellt, es gibt aber Probleme mit der Nutzerfreundlichkeit und App-Steuerelemente, die sich überschneiden und in Konflikt stehen. Diese Probleme müssen behoben werden.

5. Einsätze

Mit WindowInsets wird der App mitgeteilt, wo die System-UI über Ihren Inhalten angezeigt wird und in welchen Bereichen des Bildschirms Systemgesten Vorrang vor In-App-Gesten haben. Insets werden in Jetpack durch die Klassen WindowInsets und WindowInsetsCompat dargestellt. Wir empfehlen dringend, WindowInsetsCompat zu verwenden, um ein einheitliches Verhalten auf allen API-Ebenen zu erzielen.

System-Insets und obligatorische System-Insets

Die folgenden Inset-APIs sind die am häufigsten verwendeten Inset-Typen:

  • System-Window-Insets:Sie geben an, wo die System-UI über Ihrer App angezeigt wird. Wir erläutern, wie Sie System-Insets verwenden können, um Steuerelemente von den Systemleisten zu entfernen.
  • System-Gesten-Insets:Sie geben alle Gestenbereiche zurück. In diesen Regionen können In-App-Wischsteuerungen versehentlich Systemgesten auslösen.
  • Obligatorische Gesten-Insets:Sie sind eine Teilmenge der Systemgesten-Insets und können nicht überschrieben werden. Sie zeigen die Bereiche des Bildschirms an, in denen das Verhalten der System-Gesten immer Vorrang vor In-App-Gesten hat.

App-Steuerelemente mit Insets verschieben

Nachdem Sie nun mehr über Inset-APIs wissen, können Sie die App-Steuerelemente korrigieren. Gehen Sie dazu so vor:

  1. Rufen Sie eine Instanz von playerLayout aus der view-Objektinstanz ab.
  2. Fügen Sie der playerView ein OnApplyWindowInsetsListener hinzu.
  3. Ansicht vom Gestenbereich entfernen: Ermitteln Sie den System-Inset-Wert für den unteren Rand und erhöhen Sie den Padding-Wert der Ansicht um diesen Betrag. Um das Padding der Ansicht entsprechend zu aktualisieren, addieren Sie zum [Wert für das untere Padding der App] den [Wert für den unteren Inset-Wert des Systems].

Sehen Sie sich das folgende Codebeispiel für NowPlayingFragment.kt an:

playerView = view.findViewById(R.id.playerLayout)
playerView.setOnApplyWindowInsetsListener { view, insets ->
   view.updatePadding(
      bottom = insets.systemWindowInsetBottom + view.paddingBottom
   )
   insets
}
  1. Starte die App und wähle einen Titel aus. Es scheint sich nichts an den Player-Steuerelementen zu ändern. Wenn Sie einen Haltepunkt hinzufügen und die App im Debug-Modus ausführen, sehen Sie, dass der Listener nicht aufgerufen wird.
  2. Um das Problem zu beheben, wechseln Sie zu FragmentContainerView. Dort wird das Problem automatisch behoben. Öffnen Sie activity_main.xml und ändern Sie FrameLayout in FragmentContainerView.

Sehen Sie sich das folgende Codebeispiel für activity_main.xml an:

<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fragmentContainer"
    tools:context="com.example.android.uamp.MainActivity"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  1. Führen Sie die App noch einmal aus und rufen Sie den Playerbildschirm auf. Die unteren Player-Steuerelemente werden vom unteren Bereich für Touch-Gesten weg verschoben.

Die App-Steuerelemente funktionieren jetzt mit der Gestensteuerung, aber sie bewegen sich mehr als erwartet. Sie müssen dieses Problem beheben.

Aktuelles Padding und aktuelle Ränder beibehalten

Wenn Sie zu anderen Apps wechseln oder zum Startbildschirm gehen und zur App zurückkehren, ohne sie zu schließen, werden die Player-Steuerelemente jedes Mal nach oben verschoben.

Das liegt daran, dass die App jedes Mal, wenn die Aktivität beginnt, requestApplyInsets() auslöst. Auch ohne diesen Aufruf kann WindowInsets jederzeit während des Lebenszyklus einer Ansicht mehrmals gesendet werden.

Der aktuelle InsetListener auf dem playerView funktioniert beim ersten Mal einwandfrei, wenn Sie den Wert für „inset bottom“ zum Wert für das untere Padding der App hinzufügen, der in activity_main.xml deklariert ist. Bei nachfolgenden Aufrufen wird der Wert für „inset bottom“ jedoch weiterhin zum bereits aktualisierten unteren Padding der Ansicht hinzugefügt.

So beheben Sie das Problem:

  1. Notieren Sie den ursprünglichen Wert für den Ansichtsabstand. Erstellen Sie einen neuen „val“ und speichern Sie den ursprünglichen Wert für das Ansichtspadding von playerView direkt vor dem Listener-Code.

Sehen Sie sich das folgende Codebeispiel für NowPlayingFragment.kt an:

   val initialPadding = playerView.paddingBottom
  1. Mit diesem Startwert können Sie das untere Padding der Ansicht aktualisieren, sodass Sie den aktuellen Wert für das untere Padding der App nicht verwenden müssen.

Sehen Sie sich das folgende Codebeispiel für NowPlayingFragment.kt an:

   playerView.setOnApplyWindowInsetsListener { view, insets ->
            view.updatePadding(bottom = insets.systemWindowInsetBottom + initialPadding)
            insets
        }
  1. Führen Sie die App noch einmal aus. Zwischen Apps wechseln und zum Startbildschirm zurückkehren Wenn Sie die App zurückgeben, befinden sich die Player-Steuerelemente direkt über dem Bereich für die Touch-Gesten.

App-Steuerelemente neu gestalten

Die Fortschrittsanzeige des Players befindet sich zu nah am unteren Bereich für Gesten. Das bedeutet, dass Nutzer versehentlich die Startbildschirm-Geste auslösen können, wenn sie horizontal wischen. Wenn Sie das Padding noch weiter erhöhen, kann das Problem behoben werden, aber der Player wird möglicherweise höher als gewünscht positioniert.

Mit Insets lassen sich Konflikte mit Gesten beheben. Manchmal können Sie sie aber auch durch kleine Designänderungen ganz vermeiden. So gestalten Sie die Player-Steuerelemente neu, um Konflikte mit Gesten zu vermeiden:

  1. Öffnen Sie fragment_nowplaying.xml. Wechseln Sie zur Designansicht und wählen Sie ganz unten SeekBar aus:

74918dec3926293f.png

  1. Wechseln Sie zur Codeansicht.
  2. Wenn Sie die SeekBar an den Anfang der playerLayout verschieben möchten, ändern Sie layout_constraintTop_toBottomOf der SeekBar in parent.
  3. Wenn Sie andere Elemente in playerView an den unteren Rand von SeekBar anpassen möchten, ändern Sie layout_constraintTop_toTopOf von „parent“ zu @+id/seekBar für media_button, title und position.

Sehen Sie sich das folgende Codebeispiel für fragment_nowplaying.xml an:

<androidx.constraintlayout.widget.ConstraintLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:padding="8dp"
   android:layout_gravity="bottom"
   android:background="@drawable/media_overlay_background"
   android:id="@+id/playerLayout">

   <ImageButton
       android:id="@+id/media_button"
       android:layout_width="@dimen/exo_media_button_width"
       android:layout_height="@dimen/exo_media_button_height"
       android:background="?attr/selectableItemBackground"
       android:scaleType="centerInside"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintTop_toTopOf="@+id/seekBar"
       app:srcCompat="@drawable/ic_play_arrow_black_24dp"
       tools:ignore="ContentDescription" />

   <TextView
       android:id="@+id/title"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginTop="8dp"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Title"
       app:layout_constraintTop_toTopOf="@+id/seekBar"
       app:layout_constraintLeft_toRightOf="@id/media_button"
       app:layout_constraintRight_toLeftOf="@id/position"
       tools:text="Song Title" />

   <TextView
       android:id="@+id/subtitle"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Subtitle"
       app:layout_constraintTop_toBottomOf="@+id/title"
       app:layout_constraintLeft_toRightOf="@id/media_button"
       app:layout_constraintRight_toLeftOf="@id/position"
       tools:text="Artist" />

   <TextView
       android:id="@+id/position"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginTop="8dp"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Title"
       app:layout_constraintTop_toTopOf="@+id/seekBar"
       app:layout_constraintRight_toRightOf="parent"
       tools:text="0:00" />

   <TextView
       android:id="@+id/duration"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_marginStart="@dimen/text_margin"
       android:layout_marginEnd="@dimen/text_margin"
       android:ellipsize="end"
       android:maxLines="1"
       android:textAppearance="@style/TextAppearance.Uamp.Subtitle"
       app:layout_constraintTop_toBottomOf="@id/position"
       app:layout_constraintRight_toRightOf="parent"
       tools:text="0:00" />

   <SeekBar
       android:id="@+id/seekBar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  1. Führen Sie die App aus und interagieren Sie mit dem Player und der Suchleiste.

Diese minimalen Designänderungen verbessern die App erheblich.

6. Gesture Exclusion API

Die Player-Steuerelemente für Gestenkonflikte im Bereich für Home-Gesten wurden korrigiert. Der Bereich für die Zurück-Geste kann auch zu Konflikten mit den App-Steuerelementen führen. Der folgende Screenshot zeigt, dass sich die Suchleiste des Players derzeit sowohl im Bereich für die rechte als auch für die linke Zurück-Geste befindet:

e6d98e94dcf83dde.png

SeekBar verarbeitet automatisch Konflikte mit Gesten. Möglicherweise müssen Sie jedoch andere UI-Komponenten verwenden, die zu Konflikten mit Gesten führen. In diesen Fällen können Sie mit Gesture Exclusion API die Zurück-Geste teilweise deaktivieren.

Gesture Exclusion API verwenden

Rufen Sie setSystemGestureExclusionRects() für Ihre Ansicht mit einer Liste von rect-Objekten auf, um eine Ausschlusszone für Gesten zu erstellen. Diese rect-Objekte entsprechen den Koordinaten der ausgeschlossenen rechteckigen Bereiche. Dieser Aufruf muss in den Methoden onLayout() oder onDraw() der Ansicht erfolgen. Führen Sie zu diesem Zweck die folgenden Schritte aus:

  1. Erstellen Sie ein neues Paket mit dem Namen view.
  2. Um diese API aufzurufen, erstellen Sie eine neue Klasse mit dem Namen MySeekBar und erweitern Sie AppCompatSeekBar.

Sehen Sie sich das folgende Codebeispiel für MySeekBar.kt an:

class MySeekBar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = android.R.attr.seekBarStyle
) : androidx.appcompat.widget.AppCompatSeekBar(context, attrs, defStyle) {

}
  1. Erstellen Sie eine neue Methode mit dem Namen updateGestureExclusion().

Sehen Sie sich das folgende Codebeispiel für MySeekBar.kt an:

private fun updateGestureExclusion() {

}
  1. Fügen Sie eine Prüfung hinzu, um diesen Aufruf bei API-Level 28 oder niedriger zu überspringen.

Sehen Sie sich das folgende Codebeispiel für MySeekBar.kt an:

private fun updateGestureExclusion() {
        // Skip this call if we're not running on Android 10+
        if (Build.VERSION.SDK_INT < 29) return
}
  1. Da die Gesture Exclusion API ein Limit von 200 dp hat, sollte nur der Daumen der Seekbar ausgeschlossen werden. Rufen Sie eine Kopie der Grenzen der Suchleiste ab und fügen Sie jedes Objekt einer veränderlichen Liste hinzu.

Sehen Sie sich das folgende Codebeispiel für MySeekBar.kt an:

private val gestureExclusionRects = mutableListOf<Rect>()

private fun updateGestureExclusion() {
    // Skip this call if we're not running on Android 10+
    if (Build.VERSION.SDK_INT < 29) return

    thumb?.also { t ->
        gestureExclusionRects += t.copyBounds()
    }
}
  1. Rufen Sie systemGestureExclusionRects() mit den von Ihnen erstellten gestureExclusionRects-Listen auf.

Sehen Sie sich das folgende Codebeispiel für MySeekBar.kt an:

private val gestureExclusionRects = mutableListOf<Rect>()

private fun updateGestureExclusion() {
    // Skip this call if we're not running on Android 10+
    if (Build.VERSION.SDK_INT < 29) return

    thumb?.also { t ->
        gestureExclusionRects += t.copyBounds()
    }
    // Finally pass our updated list of rectangles to the system
    systemGestureExclusionRects = gestureExclusionRects
}
  1. Rufen Sie die Methode updateGestureExclusion() über onDraw() oder onLayout() auf. Überschreiben Sie onDraw() und fügen Sie einen Aufruf von updateGestureExclusion hinzu.

Sehen Sie sich das folgende Codebeispiel für MySeekBar.kt an:

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    updateGestureExclusion()
}
  1. Sie müssen die SeekBar-Referenzen aktualisieren. Öffnen Sie fragment_nowplaying.xml, um zu beginnen.
  2. Ändern Sie SeekBar zu com.example.android.uamp.view.MySeekBar.

Sehen Sie sich das folgende Codebeispiel für fragment_nowplaying.xml an:

<com.example.android.uamp.view.MySeekBar
    android:id="@+id/seekBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="parent" />
  1. Wenn Sie die SeekBar-Verweise in NowPlayingFragment.kt aktualisieren möchten, öffnen Sie NowPlayingFragment.kt und ändern Sie den Typ von positionSeekBar in MySeekBar. Um den Variablentyp anzupassen, ändern Sie die SeekBar-Generics für den findViewById-Aufruf in MySeekBar.

Sehen Sie sich das folgende Codebeispiel für NowPlayingFragment.kt an:

val positionSeekBar: MySeekBar = view.findViewById<MySeekBar>(
     R.id.seekBar
).apply { progress = 0 }
  1. Führen Sie die App aus und interagieren Sie mit SeekBar. Wenn weiterhin Konflikte mit Gesten auftreten, können Sie die Daumenbegrenzungen in MySeekBar anpassen. Achten Sie darauf, keine unnötig großen Ausschlussbereiche für Gesten zu erstellen, da dies andere potenzielle Aufrufe für den Ausschluss von Gesten einschränkt und zu einem inkonsistenten Verhalten für den Nutzer führt.

7. Glückwunsch

Glückwunsch! Sie haben gelernt, wie Sie Konflikte mit Systemgesten vermeiden und lösen können.

Sie haben Ihre App im Vollbildmodus verwendet, als Sie die Edge-to-Edge-Funktion erweitert und Insets verwendet haben, um App-Steuerelemente von Gestenzonen zu entfernen. Außerdem haben Sie gelernt, wie Sie die System-Touchgeste „Zurück“ für App-Steuerelemente deaktivieren.

Sie kennen jetzt die wichtigsten Schritte, die erforderlich sind, damit Ihre Apps mit Systemgesten funktionieren.

Zusätzliche Materialien

Referenzdokumente