Halo semuanya! Saya ingin berbicara tentang fitur dalam karya
Navigasi Arsitektur Komponen , karena itu saya mempunyai kesan ambigu perpustakaan.
Artikel ini bukan panduan langkah demi langkah, ini menghilangkan detail implementasi untuk fokus pada poin-poin utama. Ada banyak kasus penggunaan
serupa di Internet (ada juga terjemahan) - mereka akan membantu Anda berkenalan dengan perpustakaan. Juga, sebelum membaca, saya mengusulkan untuk mempelajari
dokumentasinya .
Saya harus mengatakan segera bahwa saya pasti menganggap perpustakaan bermanfaat dan tidak mengecualikan kemungkinan penyalahgunaan, tetapi saya mungkin mencoba semuanya sebelum menulis artikel ini.Jadi, berikut adalah skenario dalam implementasi yang harapan untuk fungsi tidak sesuai dengan kenyataan dalam implementasi:
- beralih antar item menu di laci navigasi
- penemuan Kegiatan baru dengan grafik navigasinya
- meneruskan parameter ke startDestination
Beralih di antara item menu
Ini adalah salah satu fitur yang mempengaruhi keputusan untuk menggunakan Komponen Navigasi.
Anda hanya perlu membuat id item menu identik
activity_main_drawer.xml<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:showIn="navigation_view"> <group android:checkableBehavior="single"> <item android:id="@+id/importFragment" android:icon="@drawable/ic_menu_camera" android:title="Import"/> <item android:id="@+id/galleryFragment" android:icon="@drawable/ic_menu_gallery" android:title="Gallery"/> <item android:id="@+id/slideshowFragment" android:icon="@drawable/ic_menu_slideshow" android:title="Slideshow"/>
dan id layar (tujuan dalam grafik navigasi)
mobile_navigation.xml <?xml version="1.0" encoding="utf-8"?> <navigation 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/mobile_navigation" app:startDestination="@id/importFragment"> <fragment android:id="@+id/importFragment" android:name="com.xiii.navigationapplication.ImportFragment" android:label="fragment_import" tools:layout="@layout/fragment_import"/> <fragment android:id="@+id/galleryFragment" android:name="com.xiii.navigationapplication.GalleryFragment" android:label="fragment_gallery" tools:layout="@layout/fragment_gallery"/> <fragment android:id="@+id/slideshowFragment" android:name="com.xiii.navigationapplication.SlideshowFragment" android:label="fragment_slideshow" tools:layout="@layout/fragment_slideshow"/> </navigation>
maka Anda perlu mengaitkan menu dengan pengontrol navigasi:
MainActivity.kt class MainActivity : AppCompatActivity() { private val navController by lazy(LazyThreadSafetyMode.NONE) { Navigation.findNavController(this, R.id.nav_host_fragment) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar)
Navigasi di menu telah berfungsi - bukankah itu keajaiban?!
Perhatikan "hamburger" (ikon menu), saat beralih di antara item menu, ia mengubah statusnya menjadi tombol "kembali". Perilaku ini tampak
tidak biasa (seperti
familier - seperti dalam aplikasi pasar bermain) dan, untuk sementara waktu, saya mencoba mencari tahu apa yang salah?
Itu saja! Setelah membaca dokumentasi tentang prinsip-prinsip navigasi (yaitu, poin
dua dan
tiga ), saya menyadari bahwa "hamburger" ditampilkan hanya untuk
startDestination , atau lebih tepatnya, dengan cara ini: tombol kembali ditampilkan untuk semua orang kecuali
startDestination . Situasi dapat diubah dengan menerapkan berbagai trik dalam berlangganan (
addOnNavigatedListener () ) untuk mengubah
tujuan , tetapi mereka bahkan tidak boleh dijelaskan. Ini berfungsi seperti ini, Anda harus menyetujui.
Membuka Kegiatan baru
Aktivitas dapat bertindak sebagai
host navigasi dan, pada saat yang sama, dalam grafik navigasi dapat bertindak sebagai salah satu
tujuan . Membuka suatu Kegiatan tanpa grafik navigasi bersarang berfungsi
seperti yang diharapkan , mis. Panggilan:
navController.navigate(R.id.editActivity)
akan melakukan transisi (seperti dalam kasus fragmen) dan membuka Aktivitas yang diminta.
Jauh lebih menarik untuk mempertimbangkan kasus ketika Aktivitas target itu sendiri bertindak sebagai
host navigasi , yaitu opsi 2 dari
dokumentasi :

Sebagai contoh, mari kita lihat Kegiatan untuk menambahkan catatan. Ini akan
berisi fragmen utama dengan
bidang input
EditFragment , itu akan menjadi
StartDestination dalam grafik navigasi. Mari kita asumsikan bahwa ketika mengedit kita perlu melampirkan foto, untuk ini kita akan pergi ke
PhotoFragment untuk mendapatkan gambar dari kamera. Grafik navigasi akan terlihat seperti ini:
edit_navigation.xml <?xml version="1.0" encoding="utf-8"?> <navigation 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/edit_navigation" app:startDestination="@id/editFragment"> <fragment android:id="@+id/editFragment" android:name="com.xiii.navigationapplication.ui.edit.EditFragment" android:label="fragment_edit" tools:layout="@layout/fragment_edit"> <action android:id="@+id/action_editFragment_to_photoFragment" app:destination="@id/photoFragment"/> </fragment> <fragment android:id="@+id/photoFragment" android:name="com.xiii.navigationapplication.ui.edit.PhotoFragment" android:label="fragment_photo" tools:layout="@layout/fragment_photo"/> </navigation>
EditActivity tidak jauh berbeda dari
MainActivity . Perbedaan utama adalah bahwa tidak ada menu di
EditActivity :
EditActivity.kt class EditActivity : AppCompatActivity() { private val navController by lazy(LazyThreadSafetyMode.NONE) { Navigation.findNavController(this, R.id.nav_host_fragment) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_edit) setSupportActionBar(toolbar) // "" toolbar NavigationUI.setupWithNavController(toolbar, navController) } override fun onSupportNavigateUp() = navController.navigateUp() fun takePhoto(view: View) { navController.navigate(R.id.action_editFragment_to_photoFragment) } }
Aktivitas terbuka, navigasi di dalamnya berfungsi:
Sekali lagi, perhatikan tombol navigasi di bilah alat - pada awal
EditFragment tidak ada tombol "Kembali ke aktivitas Orang
Tua " (tapi saya ingin). Dari sudut pandang dokumentasi, semuanya legal di sini: grafik navigasi baru, nilai
startDestination baru, tombol "Kembali" tidak ditampilkan di
startDestination , akhir.
Bagi mereka yang ingin kembali ke
perilaku biasa dengan aktivitas orang tua , sambil mempertahankan fungsionalitas untuk beralih antar fragmen, saya dapat menawarkan pendekatan
kruk ini:
1. Tentukan Aktivitas induk dalam manifes <activity android:name=".EditActivity" android:parentActivityName=".MainActivity" android:theme="@style/AppTheme.NoActionBar"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity" /> </activity>
2. Tambahkan langganan di mana kami akan mengganti id startDestination class EditActivity : AppCompatActivity() { private val navController by lazy(LazyThreadSafetyMode.NONE) { Navigation.findNavController(this, R.id.nav_host_fragment) } private var isStartDestination = true override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_edit) setSupportActionBar(toolbar) val startDestinationId = navController.graph.startDestination // id, NavigationUI.ActionBarOnNavigatedListener // destination startDestination navController.addOnNavigatedListener { controller, destination -> isStartDestination = destination.id == startDestinationId // R.id.fake_start_destination id controller.graph.startDestination = if (isStartDestination) R.id.fake_start_destination else startDestinationId } // "" toolbar NavigationUI.setupActionBarWithNavController(this, navController) } override fun onSupportNavigateUp(): Boolean { // startDestination Navigation Component return if (isStartDestination) super.onSupportNavigateUp() else navController.navigateUp() } fun takePhoto(view: View) { navController.navigate(R.id.action_editFragment_to_photoFragment) } }
Berlangganan diperlukan agar untuk
NavigationUI.ActionBarOnNavigatedListener semua tujuan tidak startDestination . Dengan demikian,
NavigationUI.ActionBarOnNavigatedListener tidak akan menyembunyikan tombol navigasi (lihat sumber untuk detail). Tambahkan ke ini pemrosesan
onSupportNavigateUp () secara teratur di
startDestination dan dapatkan yang kita inginkan.
Perlu dikatakan bahwa solusinya jauh dari ideal, jika hanya karena itu adalah intervensi yang tidak terlihat dalam perilaku perpustakaan. Saya percaya bahwa masalah dapat muncul ketika menggunakan
tautan dalam (saya belum mengujinya).
Melewati parameter ke startDestination
Komponen Navigasi memiliki
mekanisme untuk meneruskan parameter dari satu
tujuan ke tujuan lain. Bahkan ada
alat untuk memastikan keamanan tipe melalui pembuatan kode (tidak buruk).
Sekarang kita akan menganalisis kasus ini, karena itu saya tidak dapat menempatkan lima solid untuk fungsional ini.
Mari kita kembali ke
EditActivity , skenario yang cukup akrab ketika satu Kegiatan digunakan untuk membuat dan mengedit objek. Saat Anda membuka objek untuk diedit di Aktivitas, Anda perlu mentransfer, misalnya, id objek - mari kita lakukan secara teratur:
1. Tambahkan parameter ke grafik untuk EditActivitySaya menambahkan parameter langsung ke elemen root dari grafik (navigasi), tetapi dapat ditambahkan ke fragmen target. Dari ini, hanya metode mendapatkan parameter yang akan berubah.
<?xml version="1.0" encoding="utf-8"?> <navigation 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/edit_navigation" app:startDestination="@id/editFragment"> <argument android:name="id" app:argType="integer"/> <fragment android:id="@+id/editFragment" android:name="com.xiii.navigationapplication.ui.edit.EditFragment" android:label="fragment_edit" tools:layout="@layout/fragment_edit"> <action android:id="@+id/action_editFragment_to_photoFragment" app:destination="@id/photoFragment"/> </fragment> <fragment android:id="@+id/photoFragment" android:name="com.xiii.navigationapplication.ui.edit.PhotoFragment" android:label="fragment_photo" tools:layout="@layout/fragment_photo"/> </navigation>
2. Tambahkan aksi ke grafik utamaSaya menambahkan menambahkan dan mengedit tindakan ke salah satu fragmen, sehingga hanya akan tersedia dari itu.
<?xml version="1.0" encoding="utf-8"?> <navigation 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/mobile_navigation" app:startDestination="@id/importFragment"> <fragment android:id="@+id/importFragment" android:name="com.xiii.navigationapplication.ImportFragment" android:label="fragment_import" tools:layout="@layout/fragment_import"> <action android:id="@+id/add" app:destination="@id/editActivity"> <argument android:name="id" app:argType="integer" android:defaultValue="0"/> </action> <action android:id="@+id/edit" app:destination="@id/editActivity"> <argument android:name="id" app:argType="integer"/> </action> </fragment> <fragment android:id="@+id/galleryFragment" android:name="com.xiii.navigationapplication.GalleryFragment" android:label="fragment_gallery" tools:layout="@layout/fragment_gallery"/> <fragment android:id="@+id/slideshowFragment" android:name="com.xiii.navigationapplication.SlideshowFragment" android:label="fragment_slideshow" tools:layout="@layout/fragment_slideshow"/> <activity android:id="@+id/editActivity" android:name="com.xiii.navigationapplication.EditActivity" android:label="activity_edit" tools:layout="@layout/activity_edit"/> </navigation>
3. Siapkan parameter dan minta transisiDalam contoh ini,
ImportFragmentDirections adalah kelas safe-args yang dibuat secara otomatis.
val direction = ImportFragmentDirections.edit(123 ) navController.navigate(direction)
3. Dapatkan id dalam fragmen class EditFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
Anda, tentu saja, memperhatikan fitur-fitur untuk mendapatkan parameter di
EditFragment . Ini berfungsi karena tindakan edit (dari titik 1) meneruskan argumen ke
EditActivity , dan untuk sebagian alasannya, adalah
serakah bahwa tidak meneruskannya ke grafik (misalnya, dengan memanggil
navController.graph.setDefaultArguments () ). Fitur ini dapat dielakkan dengan menyiapkan
pengontrol navigasi secara manual. Satu cara dijelaskan pada
StackOwerflow .
Mungkin kesulitan terbesar akan muncul ketika digunakan secara bersamaan sebagai
startDestination dan
tujuan yang biasa. Yaitu, ketika meneruskan dan meneruskan parameter ke
startDestination dari
tujuan lain mana pun
dari grafik ini, fragmen harus menentukan secara independen di mana mengekstrak parameter dari: dari argumen atau dari intent.extras. Ini harus diingat ketika merancang transisi dengan melewati parameter.
Meringkas, saya ingin mencatat bahwa saya sendiri belum berhenti menggunakan perpustakaan dan, meskipun ada
kekurangan fitur yang terdaftar, saya merasa cukup berguna untuk merekomendasikan untuk digunakan. Saya sangat berharap bahwa dalam rilis berikutnya situasinya akan berubah, setidaknya dengan transfer parameter ke
startDestination .
Terima kasih atas perhatian anda Kode kerja Anda!
Sumber untuk artikel ini diposting di
GitHub .