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.
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.
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à.
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.