Gestione delle modifiche alla configurazione

UI e navigazione adattabili

Per offrire agli utenti la migliore esperienza di navigazione possibile, devi: forniscono un'interfaccia utente di navigazione personalizzata in base a larghezza, altezza la larghezza minima del dispositivo dell'utente. Ti consigliamo di utilizzare un barra delle app in basso, Sempre presente o comprimibile riquadro di navigazione a scomparsa, ferrovia, o magari qualcosa di completamente nuovo in base allo spazio disponibile sullo schermo e ai e lo stile unico dell'app.

esempi di barra laterale, riquadri di navigazione a scomparsa e barra delle app in basso
Figura 1. Esempi di barra laterale, riquadri di navigazione a scomparsa e un barra delle app in basso.

Il material design guida all'architettura del prodotto fornisce un contesto aggiuntivo e considerazioni per la creazione di una UI reattiva, è una UI che si adatta in modo dinamico ai cambiamenti ambientali. Alcuni esempi le modifiche ambientali includono le modifiche a larghezza, altezza, orientamento preferenza della lingua dell'utente. Queste proprietà ambientali sono nel complesso definita configurazione del dispositivo.

Quando una o più di queste proprietà cambiano in fase di runtime, il sistema operativo Android risponde di distruggere e ricreare le attività e i frammenti della tua app. Pertanto, la cosa migliore che puoi fare per supportare un'interfaccia utente reattiva su Android è di utilizzare qualificatori di configurazione delle risorse ove opportuno e evitare l'utilizzo di dimensioni di layout hardcoded.

Implementazione della navigazione globale in una UI reattiva

L'implementazione della navigazione globale come parte di una UI reattiva inizia con sull'attività che ospita il grafico di navigazione. Per un esempio pratico, consulta elimina Codelab per la navigazione. Il codelab utilizza una classe NavigationView per visualizzare il menu di navigazione, come mostrato nella Figura 2. Durante l'esecuzione su un dispositivo che viene visualizzato con una larghezza di almeno 960 dp, il valore NavigationView è sempre sullo schermo.

Il codelab per la navigazione utilizza una vista di navigazione sempre visibile
            quando la larghezza del dispositivo è di almeno 960 dp
Figura 2. Il codelab Navigazione utilizza un NavigationView per visualizzare il menu di navigazione.

Altri orientamenti e dimensioni dei dispositivi cambiano in modo dinamico DrawerLayout oppure BottomNavigationView dell'oggetto o eliminare definitivamente una versione archiviata, in base alle necessità.

una visualizzazione di navigazione dal basso e un layout a scomparsa, utilizzati per la navigazione
            menu in base alle esigenze nei layout dei dispositivi più piccoli
Figura 3. Il codelab Navigazione utilizza BottomNavigationView e DrawerLayout per visualizzare il menu di navigazione sui dispositivi più piccoli.

Puoi implementare questo comportamento creando tre layout diversi, dove ciascuno che definisce gli elementi di navigazione desiderati e la gerarchia di visualizzazione in base ai configurazione attuale del dispositivo.

La configurazione a cui si applica ogni layout è determinata dalla directory in cui viene inserito il file di layout. Ad esempio, NavigationView file di layout presente nella directory res/layout-w960dp.

<!-- res/layout-w960dp/navigation_activity.xml -->
<RelativeLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context="com.example.android.codelabs.navigation.MainActivity">

   <com.google.android.material.navigation.NavigationView
       android:id="@+id/nav_view"
       android:layout_width="wrap_content"
       android:layout_height="match_parent"
       android:layout_alignParentStart="true"
       app:elevation="0dp"
       app:headerLayout="@layout/nav_view_header"
       app:menu="@menu/nav_drawer_menu" />

   <View
       android:layout_width="1dp"
       android:layout_height="match_parent"
       android:layout_toEndOf="@id/nav_view"
       android:background="?android:attr/listDivider" />

   <androidx.appcompat.widget.Toolbar
       android:id="@+id/toolbar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_alignParentTop="true"
       android:layout_toEndOf="@id/nav_view"
       android:background="@color/colorPrimary"
       android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar" />

   <androidx.fragment.app.FragmentContainerView
       android:id="@+id/my_nav_host_fragment"
       android:name="androidx.navigation.fragment.NavHostFragment"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_below="@id/toolbar"
       android:layout_toEndOf="@id/nav_view"
       app:defaultNavHost="true"
       app:navGraph="@navigation/mobile_navigation" />
</RelativeLayout>

La visualizzazione di navigazione in basso si trova nella directory res/layout-h470dp:

<!-- res/layout-h470dp/navigation_activity.xml -->
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   tools:context="com.example.android.codelabs.navigation.MainActivity">

   <androidx.appcompat.widget.Toolbar
       android:id="@+id/toolbar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:background="@color/colorPrimary"
       android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar" />

   <androidx.fragment.app.FragmentContainerView
       android:id="@+id/my_nav_host_fragment"
       android:name="androidx.navigation.fragment.NavHostFragment"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1"
       app:defaultNavHost="true"
       app:navGraph="@navigation/mobile_navigation" />

   <com.google.android.material.bottomnavigation.BottomNavigationView
       android:id="@+id/bottom_nav_view"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:menu="@menu/bottom_nav_menu" />
</LinearLayout>

Il layout del riquadro a scomparsa si trova nella directory res/layout. Utilizza questa directory per layout predefiniti senza qualificatori specifici per la configurazione:

<!-- res/layout/navigation_activity.xml -->
<androidx.drawerlayout.widget.DrawerLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/drawer_layout"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context="com.example.android.codelabs.navigation.MainActivity">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/toolbar"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:background="@color/colorPrimary"
           android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar" />

       <androidx.fragment.app.FragmentContainerView
           android:id="@+id/my_nav_host_fragment"
           android:name="androidx.navigation.fragment.NavHostFragment"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           app:defaultNavHost="true"
           app:navGraph="@navigation/mobile_navigation" />
   </LinearLayout>

   <com.google.android.material.navigation.NavigationView
       android:id="@+id/nav_view"
       android:layout_width="wrap_content"
       android:layout_height="match_parent"
       android:layout_gravity="start"
       app:menu="@menu/nav_drawer_menu" />
</androidx.drawerlayout.widget.DrawerLayout>

Android segue ordine di precedenza nel determinare quali risorse applicare. Nello specifico per questo esempio, -w960dp (o larghezza disponibile >= 960 dp) ha la precedenza su -h470dp (o disponibile altezza >= 470). Se la configurazione del dispositivo non corrisponde a nessuna di queste opzioni la risorsa di layout predefinita (res/layout/navigation_activity.xml).

Per gestire gli eventi di navigazione, devi collegare solo gli eventi che corrispondono ai widget attualmente presenti, come mostrato nell'esempio che segue.

Kotlin

class MainActivity : AppCompatActivity() {

   private lateinit var appBarConfiguration : AppBarConfiguration

   override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.navigation_activity)
      val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout)
      appBarConfiguration = AppBarConfiguration(
                  setOf(R.id.home_dest, R.id.deeplink_dest),
                  drawerLayout)

      ...

      // Initialize the app bar with the navigation drawer if present.
      // If the drawerLayout is not null here, a Navigation button will be added
      // to the app bar whenever the user is on a top-level destination.
      setupActionBarWithNavController(navController, appBarConfig)

      // Initialize the NavigationView if it is present,
      // so that clicking an item takes
      // the user to the appropriate destination.
      val sideNavView = findViewById<NavigationView>(R.id.nav_view)
      sideNavView?.setupWithNavController(navController)

      // Initialize the BottomNavigationView if it is present,
      // so that clicking an item takes
      // the user to the appropriate destination.
      val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
      bottomNav?.setupWithNavController(navController)

      ...
    }

    ...
}

Java

public class MainActivity extends AppCompatActivity {

   private AppBarConfiguration appBarConfiguration;

   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.navigation_activity);
       NavHostFragment host = (NavHostFragment) getSupportFragmentManager()
               .findFragmentById(R.id.my_nav_host_fragment);
       NavController navController = host.getNavController();

       DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);
       appBarConfiguration = new AppBarConfiguration.Builder(
               R.id.home_dest, R.id.deeplink_dest)
               .setDrawerLayout(drawerLayout)
               .build();

       // Initialize the app bar with the navigation drawer if present.
       // If the drawerLayout is not null here, a Navigation button will be added to
       // the app bar whenever the user is on a top-level destination.
       NavigationUI.setupActionBarWithNavController(
               this, navController, appBarConfiguration);


       // Initialize the NavigationView if it is present,
       // so that clicking an item takes
       // the user to the appropriate destination.
       NavigationView sideNavView = findViewById(R.id.nav_view);
       if(sideNavView != null) {
           NavigationUI.setupWithNavController(sideNavView, navController);
       }

       // Initialize the BottomNavigationView if it is present,
       // so that clicking an item takes
       // the user to the appropriate destination.
       BottomNavigationView bottomNav = findViewById(R.id.bottom_nav_view);
       if(bottomNav != null) {
           NavigationUI.setupWithNavController(bottomNav, navController);
       }

   }
}

Se la configurazione del dispositivo cambia, a meno che non venga configurati in altro modo, Android elimina l'attività dalla configurazione precedente insieme al suo viste associate. Quindi ricrea l'attività con risorse progettate per una nuova configurazione. L'attività, che viene distrutta e ricreata, raggruppa automaticamente gli elementi di navigazione globale appropriati in onCreate().

Valutare alternative ai layout con visualizzazione divisa

I layout con visualizzazione divisa, o layout principali/dettagli, erano un modo molto diffuso e consigliato per progettare tablet e altri schermi di grandi dimensioni dispositivi mobili.

Dall'introduzione dei tablet Android, l'ecosistema di dispositivi è cresciuto rapidamente. Un fattore che ha influenzato notevolmente lo spazio di progettazione di grandi l'introduzione delle modalità multi-finestra, in particolare Finestre in formato libero completamente ridimensionabili, come quelle sui dispositivi ChromeOS. Ciò pone un'enfasi molto maggiore su ogni schermata dell'app reattivo, invece di modificare la struttura di navigazione in base allo schermo. dimensioni.

Sebbene sia possibile implementare un'interfaccia di layout in visualizzazione divisa Libreria di navigazione, valutare altre alternative.

Nomi delle destinazioni

Se indichi i nomi delle destinazioni nel grafico utilizzando l'android:label assicurati di utilizzare sempre i valori delle risorse in modo che i contenuti possano comunque essere localizzati.

<navigation ...>
    <fragment
        android:id="@+id/my_dest"
        android:name="com.example.MyFragment"
        android:label="@string/my_dest_label"
        tools:layout="@layout/my_fragment" />
    ...

Con i valori delle risorse, le destinazioni hanno automaticamente il valore e vengono applicate ogni volta che la configurazione cambia.