Elastyczny interfejs i nawigacja
Aby zapewnić użytkownikom maksymalną wygodę nawigacji, należy: udostępnić interfejs użytkownika dostosowany do szerokości, wysokości mają najmniejszą szerokość ekranu urządzenia użytkownika. Możesz użyć atrybutu dolny pasek aplikacji, zawsze dostępna lub zwijana panelu nawigacji, kolej, albo zupełnie coś nowego, opartego na dostępnej przestrzeni do Twojej aplikacji.
Styl Material Design przewodnik po architekturze usługi zawiera dodatkowy kontekst i kwestie związane z tworzeniem elastycznego interfejsu użytkownika, czyli interfejs, który dynamicznie dostosowuje się do zmian środowiskowych. Kilka przykładów zmiany środowiskowe obejmują zmianę szerokości, wysokości, orientacji ustawienia języka użytkownika. Te właściwości środowiskowe są łącznie nazywaną konfiguracją urządzenia.
Gdy co najmniej jedna z tych właściwości zmienia się w czasie działania, system operacyjny Android reaguje autor: niszczenie i odtwarzanie działań i fragmentów w aplikacji. Dlatego najlepszą obsługę elastycznego interfejsu na Androidzie upewnij się, że używasz kwalifikatory konfiguracji zasobów w stosownych przypadkach, unikania stosowania rozmiarów układów zakodowanych na stałe.
Wdrażanie globalnej nawigacji w elastycznym interfejsie
Implementacja globalnej nawigacji w elastycznym interfejsie zaczyna się od
aktywność hostującą wykres nawigacji. Zapoznaj się z praktycznym przykładem,
na
Ćwiczenie z programowania dotyczące nawigacji.
Ćwiczenie w Codelabs korzysta z interfejsu NavigationView
aby wyświetlić menu nawigacyjne, tak jak na ilustracji 2. Po uruchomieniu na urządzeniu
który wyświetla się o szerokości co najmniej 960 dp, NavigationView
to zawsze
na ekranie.
Inne rozmiary i orientacje urządzeń dynamicznie przełączają się między
DrawerLayout
lub
BottomNavigationView
w razie potrzeby.
Możesz wdrożyć to rozwiązanie, tworząc 3 różne układy, z których każdy określa wymagane elementy nawigacyjne i hierarchię widoków na podstawie bieżącej konfiguracji urządzenia.
Konfiguracja, do której ma zastosowanie każdy układ, jest określana przez katalog
w której jest umieszczony plik szablonu. Na przykład NavigationView
w katalogu 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>
Dolny widok nawigacji znajduje się w katalogu 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>
Układ panelu znajduje się w katalogu res/layout
. Użyj tego katalogu do
układy domyślne bez kwalifikatorów dotyczących konkretnej konfiguracji:
<!-- 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 postępuje zgodnie z
kolejność pierwszeństwa
przy wyborze zasobów, które warto zastosować. Dotyczy tego przykładu: -w960dp
(lub dostępna szerokość >= 960 dp) ma pierwszeństwo przed kolumną -h470dp
(lub dostępna)
wysokość >= 470). Jeśli konfiguracja urządzenia nie pasuje do tych,
warunków, potem zasób domyślnego układu
(res/layout/navigation_activity.xml
).
Przy obsłudze zdarzeń nawigacji musisz podać tylko te zdarzenia, które odpowiadają do widżetów, które są obecnie dostępne, jak pokazano na przykładzie poniżej.
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); } } }
Jeśli konfiguracja urządzenia się zmieni, o ile wyraźnie nie zaznaczono inaczej,
skonfigurowanej w inny sposób,
Android niszczy aktywność z poprzedniej konfiguracji
powiązanych widoków. Następnie odtwarza to działanie za pomocą zasobów przeznaczonych do
nową konfigurację. Działanie, zniszczenie i odtworzenie,
automatycznie tworzy odpowiednie elementy globalnej nawigacji w onCreate()
.
Zastanów się nad alternatywami dla układów z podzielonym widokiem
Układy z widokiem dzielonym, czyli układy główne/szczegółowe, były kiedyś bardzo popularny i zalecany sposób projektowania na tablety i inne duże ekrany urządzenia.
Od czasu wprowadzenia tabletów z Androidem ekosystem urządzeń stale się rozwijał. bardzo szybko. Jednym z czynników, które w istotny sposób wpłynęły na architekturę dużych Urządzenia z ekranami zostały wprowadzone w trybach wielu okien. dowolnych okien, których rozmiar można w pełni zmieniać, np. na urządzeniach z ChromeOS. Dzięki temu każdy ekran aplikacji, responsywną, zamiast zmieniać strukturę nawigacji w zależności od ekranu rozmiaru.
Chociaż można wdrożyć interfejs układu podzielonego widoku, wykorzystując w bibliotece nawigacji, rozważ inne alternatywy.
Nazwy miejsc docelowych
Jeśli nazwy miejsc docelowych podajesz na wykresie za pomocą atrybutu android:label
pamiętaj, aby zawsze używać wartości zasobów, dzięki czemu treść będzie nadal
i zlokalizowania.
<navigation ...>
<fragment
android:id="@+id/my_dest"
android:name="com.example.MyFragment"
android:label="@string/my_dest_label"
tools:layout="@layout/my_fragment" />
...
Dzięki wartościom zasobów Twoje miejsca docelowe automatycznie zasobów stosowanych przy każdej zmianie konfiguracji.