UI dan navigasi responsif
Untuk memberikan pengalaman navigasi terbaik kepada pengguna, Anda harus menyediakan UI navigasi yang disesuaikan dengan lebar, tinggi, dan lebar terkecil perangkat pengguna. Anda mungkin ingin menggunakan panel aplikasi bawah, panel navigasi yang selalu ada atau dapat diciutkan, kolom samping, atau mungkin sesuatu yang benar-benar baru berdasarkan ruang layar yang tersedia dan gaya unik aplikasi Anda.
Desain material panduan arsitektur produk memberikan konteks dan pertimbangan tambahan untuk membuat UI responsif, yaitu UI yang secara dinamis menyesuaikan dengan perubahan lingkungan. Beberapa contoh perubahan lingkungan mencakup penyesuaian lebar, tinggi, orientasi, dan preferensi bahasa pengguna. Properti lingkungan ini secara keseluruhan disebut sebagai konfigurasi perangkat.
Jika satu atau beberapa properti ini berubah saat runtime, Android OS akan merespons dengan menghancurkan lalu membuat ulang aktivitas dan fragmen aplikasi Anda. Oleh karena itu, hal terbaik yang dapat Anda lakukan untuk mendukung UI responsif di Android adalah memastikan bahwa Anda menggunakan pengontrol kualitas konfigurasi resource yang sesuai dan menghindari penggunaan ukuran tata letak hard code.
Menerapkan navigasi global dalam UI responsif
Menerapkan navigasi global sebagai bagian dari UI responsif dimulai dengan
aktivitas yang menghosting grafik navigasi Anda. Untuk contoh praktis, lihat Codelab Navigation.
Codelab menggunakan NavigationView
untuk menampilkan menu navigasi, seperti yang ditunjukkan pada gambar 2. Saat dijalankan di perangkat yang merender dengan lebar minimal 960 dp, NavigationView
ini selalu ada di layar.
Ukuran dan orientasi perangkat lainnya secara dinamis beralih antara DrawerLayout
atau BottomNavigationView
sesuai kebutuhan.
Anda dapat menerapkan perilaku ini dengan membuat tiga tata letak yang berbeda, dengan setiap tata letak menentukan elemen navigasi dan hierarki tampilan yang diinginkan berdasarkan konfigurasi perangkat saat ini.
Konfigurasi tempat setiap tata letak diterapkan ditentukan oleh struktur direktori tempat file tata letak ditempatkan. Misalnya, file tata letak NavigationView
ditemukan di direktori 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>
Tampilan navigasi bawah ditemukan di direktori 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>
Tata letak panel samping ditemukan di direktori res/layout
. Gunakan direktori ini untuk tata letak default tanpa penentu khusus konfigurasi:
<!-- 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 mengikuti urutan prioritas saat menentukan resource yang akan diterapkan. Khusus untuk contoh ini, -w960dp
(atau lebar yang tersedia >= 960dp) lebih diutamakan daripada -h470dp
(atau tinggi yang tersedia >= 470). Jika konfigurasi perangkat tidak cocok dengan salah satu kondisi tersebut, resource tata letak default (res/layout/navigation_activity.xml
) akan digunakan.
Dalam menangani peristiwa navigasi, Anda hanya perlu menyiapkan peristiwa yang sesuai dengan widget yang ada saat ini, seperti yang ditunjukkan dalam contoh berikut.
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); } } }
Jika konfigurasi perangkat berubah, kecuali jika secara eksplisit dikonfigurasi sebaliknya, Android akan menghapus aktivitas dari konfigurasi sebelumnya bersama dengan tampilan terkait. Kemudian, aktivitas akan dibuat ulang dengan resource yang didesain untuk konfigurasi baru. Aktivitas tersebut, yang dihancurkan dan dibuat ulang, kemudian secara otomatis menyambungkan elemen navigasi global yang tepat di onCreate()
.
Pertimbangkan alternatif untuk tata letak tampilan terpisah
Tata letak tampilan terpisah, atau tata letak master/detail, pernah menjadi cara yang sangat populer dan direkomendasikan untuk mendesain tablet dan perangkat layar besar lainnya.
Sejak diperkenalkannya tablet Android, ekosistem perangkat telah berkembang dengan pesat. Salah satu faktor yang sangat memengaruhi ruang desain untuk perangkat layar besar adalah pengenalan mode multi-aplikasi, terutama jendela bentuk bebas yang sepenuhnya dapat diubah ukurannya, seperti pada perangkat ChromeOS. Hal ini memberikan penekanan yang jauh lebih tinggi di setiap layar aplikasi yang responsif, bukan mengubah struktur navigasi berdasarkan ukuran layar.
Meskipun Anda dapat menerapkan antarmuka tata letak tampilan terpisah menggunakan library Navigasi, Anda harus mempertimbangkan alternatif lain.
Nama tujuan
Jika Anda memberikan nama tujuan pada grafik menggunakan atribut android:label
, pastikan untuk selalu menggunakan nilai resource agar konten Anda tetap dapat dilokalkan.
<navigation ...>
<fragment
android:id="@+id/my_dest"
android:name="com.example.MyFragment"
android:label="@string/my_dest_label"
tools:layout="@layout/my_fragment" />
...
Dengan nilai resource, tujuan Anda akan otomatis menerapkan resource yang paling sesuai setiap kali konfigurasi Anda berubah.