Saya mencoba menerapkan tab untuk navigasi di aplikasi Android. Karena TabActivity dan ActivityGroup sudah tidak digunakan lagi, saya ingin mengimplementasikannya menggunakan Fragmen.
Saya tahu cara mengatur satu fragmen untuk setiap tab dan kemudian beralih fragmen ketika tab diklik. Tetapi bagaimana saya bisa memiliki tumpukan belakang terpisah untuk setiap tab?
Sebagai contoh, Fragmen A dan B akan berada di bawah Tab 1 dan Fragmen C dan D di bawah Tab 2. Ketika aplikasi dimulai, Fragmen A ditampilkan dan Tab 1 dipilih. Kemudian Fragmen A mungkin diganti dengan Fragmen B. Ketika Tab 2 dipilih, Fragmen C harus ditampilkan. Jika Tab 1 kemudian dipilih Fragmen B harus sekali lagi ditampilkan. Pada titik ini, dimungkinkan untuk menggunakan tombol kembali untuk menampilkan Fragmen A.
Juga, penting bahwa keadaan untuk setiap tab dipertahankan ketika perangkat diputar.
BR Martin
sumber
Saya sangat terlambat untuk pertanyaan ini. Tetapi karena utas ini sangat informatif dan membantu saya, saya pikir lebih baik saya mengirim dua pence saya di sini.
Saya membutuhkan aliran layar seperti ini (Desain minimalis dengan 2 tab dan 2 tampilan di setiap tab),
Saya memiliki persyaratan yang sama di masa lalu, dan saya melakukannya menggunakan
TabActivityGroup
(yang sudah usang pada saat itu juga) dan Kegiatan. Kali ini saya ingin menggunakan Fragmen.Jadi ini adalah bagaimana saya melakukannya.
1. Buat Kelas Fragmen dasar
Semua fragmen di aplikasi Anda dapat memperluas kelas Basis ini. Jika Anda ingin menggunakan fragmen khusus seperti
ListFragment
Anda harus membuat kelas dasar untuk itu juga. Anda akan jelas tentang penggunaanonBackPressed()
danonActivityResult()
jika Anda membaca posting secara penuh ..2. Buat beberapa pengidentifikasi Tab, dapat diakses di mana saja dalam proyek
tidak ada yang bisa dijelaskan di sini ..
3. Oke, Aktivitas Tab Utama - Silakan lihat komentar dalam kode ..
4. app_main_tab_fragment_layout.xml (Jika ada yang tertarik.)
5. AppTabAFirstFragment.java (Fragmen pertama di Tab A, serupa untuk semua Tab)
Ini mungkin bukan cara yang paling halus dan benar. Tapi itu berhasil dengan baik dalam kasus saya. Juga saya hanya memiliki persyaratan ini dalam mode potret. Saya tidak pernah harus menggunakan kode ini dalam proyek yang mendukung kedua orientasi. Jadi tidak bisa mengatakan tantangan apa yang saya hadapi di sana ..
EDIT:
Jika ada yang menginginkan proyek penuh, saya telah mendorong proyek sampel ke github .
sumber
Kami harus menerapkan perilaku yang persis sama dengan yang Anda gambarkan untuk aplikasi baru-baru ini. Layar dan aliran keseluruhan aplikasi sudah ditentukan sehingga kami harus tetap menggunakannya (ini adalah tiruan aplikasi iOS ...). Untungnya, kami berhasil menyingkirkan tombol kembali di layar :)
Kami meretas solusi menggunakan campuran TabActivity, FragmentActivities (kami menggunakan perpustakaan dukungan untuk fragmen) dan Fragmen. Dalam retrospektif, saya cukup yakin itu bukan keputusan arsitektur terbaik, tetapi kami berhasil membuat hal itu berfungsi. Jika saya harus melakukannya lagi, saya mungkin akan mencoba untuk melakukan solusi berbasis aktivitas yang lebih (tidak ada fragmen), atau mencoba dan hanya memiliki satu Kegiatan untuk tab dan membiarkan semua yang lain dilihat (yang saya temukan jauh lebih banyak dapat digunakan kembali daripada aktivitas keseluruhan).
Jadi persyaratannya adalah memiliki beberapa tab dan layar yang bisa di-nestable di setiap tab:
dll ...
Jadi katakan: pengguna mulai pada tab 1, menavigasi dari layar 1 ke layar 2 lalu ke layar 3, ia kemudian beralih ke tab 3 dan menavigasi dari layar 4 hingga 6; jika beralih kembali ke tab 1, ia harus melihat layar 3 lagi dan jika ia menekan Kembali ia harus kembali ke layar 2; Kembali lagi dan dia ada di layar 1; beralih ke tab 3 dan dia ada di layar 6 lagi.
Aktivitas utama dalam aplikasi adalah MainTabActivity, yang memperluas TabActivity. Setiap tab dikaitkan dengan suatu aktivitas, katakanlah ActivityInTab1, 2 dan 3. Dan kemudian setiap layar akan menjadi sebuah fragmen:
Setiap ActivityInTab hanya memegang satu fragmen pada satu waktu, dan tahu bagaimana cara mengganti satu fragmen dengan yang lain (hampir sama dengan ActvityGroup). Yang keren adalah cukup mudah untuk menjaga tumpukan back terpisah untuk setiap tab dengan cara ini.
Fungsionalitas untuk setiap ActivityInTab cukup sama: tahu cara menavigasi dari satu fragmen ke fragmen lain dan mempertahankan tumpukan belakang, jadi kami menempatkannya di kelas dasar. Sebut saja ActivityInTab:
Activity_in_tab.xml hanya ini:
Seperti yang Anda lihat, tata letak tampilan untuk setiap tab adalah sama. Itu karena itu hanya konten yang disebut FrameLayout yang akan menampung setiap fragmen. Fragmen adalah yang memiliki tampilan layar masing-masing.
Hanya untuk poin bonus, kami juga menambahkan beberapa kode kecil untuk menampilkan dialog konfirmasi ketika pengguna menekan Kembali dan tidak ada lagi fragmen untuk kembali ke:
Cukup banyak pengaturannya. Seperti yang Anda lihat, masing-masing FragmentActivity (atau hanya aktivitas di Android> 3) mengurus semua penumpukan kembali dengan FragmentManager itu sendiri.
Aktivitas seperti ActivityInTab1 akan sangat sederhana, itu hanya akan menunjukkan fragmen pertama (yaitu layar):
Kemudian, jika sebuah fragmen perlu bernavigasi ke fragmen lain, ia harus melakukan casting yang tidak menyenangkan ... tapi itu tidak terlalu buruk:
Jadi cukup banyak. Saya cukup yakin ini bukan solusi yang sangat kanonik (dan sebagian besar tentu tidak sangat baik), jadi saya ingin bertanya kepada pengembang Android berpengalaman apa yang akan menjadi pendekatan yang lebih baik untuk mencapai fungsi ini, dan jika ini bukan "bagaimana ini" dilakukan" di Android, saya akan menghargai jika Anda bisa mengarahkan saya ke beberapa link atau materi yang menjelaskan yang satu cara Android untuk pendekatan ini (tab, layar bersarang di tab, dll). Silakan merobek jawaban ini di komentar :)
Sebagai tanda bahwa solusi ini tidak terlalu baik adalah bahwa baru-baru ini saya harus menambahkan beberapa fungsi navigasi ke aplikasi. Beberapa tombol aneh yang harus membawa pengguna dari satu tab ke tab lain dan ke layar bersarang. Melakukan hal itu secara terprogram adalah rasa sakit di pantat, karena siapa-tahu-siapa masalah dan berurusan dengan kapan fragmen dan kegiatan sebenarnya dipakai dan diinisialisasi. Saya pikir itu akan jauh lebih mudah jika layar dan tab itu semua benar-benar hanya Tampilan.
Terakhir, jika Anda perlu selamat dari perubahan orientasi, penting bahwa fragmen Anda dibuat menggunakan setArguments / getArguments. Jika Anda menetapkan variabel contoh di konstruktor fragmen Anda, Anda akan kacau. Tapi untungnya itu sangat mudah diperbaiki: cukup simpan semuanya di setArguments di konstruktor dan kemudian ambil hal-hal itu dengan getArguments di onCreate untuk menggunakannya.
sumber
Ini dapat dengan mudah dicapai dengan ChildFragmentManager
Berikut adalah pos tentang ini dengan proyek terkait. Lihatlah,
http://tausiq.wordpress.com/2014/06/06/android-multiple-fragments-stack-in-each-viewpager-tab/
sumber
Menyimpan referensi kuat untuk fragmen bukan cara yang benar.
FragmentManager menyediakan
putFragment(Bundle, String, Fragment)
dansaveFragmentInstanceState(Fragment)
.Salah satu sudah cukup untuk menerapkan backstack.
Dengan menggunakan
putFragment
, alih-alih mengganti Fragmen, Anda melepaskan yang lama dan menambahkan yang baru. Inilah yang dilakukan kerangka kerja untuk mengganti transaksi yang ditambahkan ke backstack.putFragment
menyimpan indeks ke daftar Fragmen aktif saat ini dan Fragmen tersebut disimpan oleh kerangka kerja selama perubahan orientasi.Cara kedua, menggunakan
saveFragmentInstanceState
, menyimpan seluruh status fragmen ke Bundel memungkinkan Anda untuk benar-benar menghapusnya, daripada melepaskannya. Menggunakan pendekatan ini membuat tumpukan belakang lebih mudah untuk dimanipulasi, karena Anda dapat memunculkan Fragmen kapan pun Anda mau.Saya menggunakan metode kedua untuk usecase ini:
Saya tidak ingin pengguna kembali ke layar Daftar, dari yang ketiga, dengan menekan tombol kembali. Saya juga melakukan animasi flip di antara mereka (menggunakan
onCreateAnimation
), sehingga solusi hacky tidak akan berfungsi, minimal tanpa pengguna jelas melihat ada sesuatu yang tidak benar.Ini adalah kasus penggunaan yang valid untuk backstack khusus, melakukan apa yang diharapkan pengguna ...
sumber
Penolakan:
Saya merasa ini adalah tempat terbaik untuk mengirim solusi terkait yang telah saya kerjakan untuk jenis masalah serupa yang tampaknya merupakan barang standar Android. Ini tidak akan menyelesaikan masalah untuk semua orang, tetapi mungkin membantu beberapa orang.
Jika perbedaan utama antara fragmen Anda hanya data yang mencadangkannya (yaitu, tidak banyak perbedaan tata letak yang besar), maka Anda mungkin tidak perlu benar-benar mengganti fragmen, tetapi hanya menukar data yang mendasarinya dan menyegarkan tampilan.
Berikut ini deskripsi dari satu contoh yang mungkin untuk pendekatan ini:
Saya memiliki aplikasi yang menggunakan ListViews. Setiap item dalam daftar adalah orang tua dengan sejumlah anak. Saat Anda mengetuk item, daftar baru harus dibuka dengan anak-anak itu, dalam tab ActionBar yang sama dengan daftar aslinya. Daftar bersarang ini memiliki tata letak yang sangat mirip (beberapa penyesuaian bersyarat di sana-sini mungkin), tetapi datanya berbeda.
Aplikasi ini memiliki beberapa lapisan keturunan di bawah daftar induk awal dan kami mungkin atau mungkin tidak memiliki data dari server pada saat pengguna mencoba mengakses kedalaman tertentu di luar yang pertama. Karena daftar dibuat dari kursor basis data, dan fragmen menggunakan loader kursor dan adaptor kursor untuk mengisi tampilan daftar dengan item daftar, semua yang perlu terjadi ketika klik terdaftar adalah:
1) Buat adaptor baru dengan bidang 'ke' dan 'dari' yang sesuai yang akan cocok dengan tampilan item baru yang ditambahkan ke daftar dan kolom dikembalikan oleh kursor baru.
2) Tetapkan adaptor ini sebagai adaptor baru untuk ListView.
3) Bangun URI baru berdasarkan item yang diklik dan mulai ulang pemuat kursor dengan URI baru (dan proyeksi). Dalam contoh ini, URI dipetakan ke permintaan tertentu dengan argumen pilihan diturunkan dari UI.
4) Ketika data baru telah dimuat dari URI, tukar kursor yang terkait dengan adaptor ke kursor baru, dan daftar kemudian akan di-refresh.
Tidak ada backstack yang terkait dengan ini karena kami tidak menggunakan transaksi, jadi Anda harus membuat sendiri, atau memutar kueri secara terbalik saat mundur dari hierarki. Ketika saya mencoba ini, pertanyaannya cukup cepat sehingga saya hanya menjalankannya lagi di oNBackPressed () hingga saya berada di puncak hierarki, pada titik mana kerangka kerja mengambil alih tombol kembali lagi.
Jika Anda menemukan diri Anda dalam situasi yang sama, pastikan untuk membaca dokumen: http://developer.android.com/guide/topics/ui/layout/listview.html
http://developer.android.com/reference/android/support/v4/app/LoaderManager.LoaderCallbacks.html
Saya harap ini membantu seseorang!
sumber
Saya memiliki masalah yang persis sama dan mengimplementasikan proyek github open source yang mencakup tab yang ditumpuk, navigasi kembali ke atas dan diuji dan didokumentasikan dengan baik:
https://github.com/SebastianBaltesObjectCode/PersistentFragmentTabs
sumber
Ini adalah masalah yang kompleks karena Android hanya menangani 1 back stack, tetapi ini layak. Butuh waktu berhari-hari untuk membuat perpustakaan bernama Tab Stacker yang melakukan persis seperti yang Anda cari: riwayat fragmen untuk setiap tab. Ini adalah open source dan sepenuhnya didokumentasikan, dan dapat dimasukkan dengan mudah dengan gradle. Anda dapat menemukan perpustakaan di github: https://github.com/smart-fun/TabStacker
Anda juga dapat mengunduh aplikasi sampel untuk melihat bahwa perilaku tersebut sesuai dengan kebutuhan Anda:
https://play.google.com/apps/testing/fr.arnaudguyon.tabstackerapp
Jika Anda memiliki pertanyaan jangan ragu untuk mengirim email.
sumber
Saya ingin menyarankan solusi saya sendiri jika seseorang mencari dan ingin mencoba dan memilih yang terbaik untuk kebutuhannya.
https://github.com/drusak/tabactivity
Tujuan membuat perpustakaan cukup dangkal - mengimplementasikannya seperti iPhone.
Keuntungan utama:
sumber
ListFragment
s selainFragment
s jadi saya menggandakan BaseTabFragment.java ke BaseTabListFragment.java dan telah memperpanjang ListFragment. Kemudian saya harus mengubah berbagai bagian dalam kode di mana ia selalu dianggap mengharapkan BaseTabFragment. Apakah ada cara yang lebih baik?Solusi sederhana:
Setiap kali Anda mengubah panggilan tampilan tab / root:
Ini akan menghapus BackStack. Ingat untuk memanggil ini sebelum Anda mengubah fragmen root.
Dan tambahkan fragmen dengan ini:
Perhatikan
.addToBackStack(null)
dantransaction.add
misalnya dapat diubah dengantransaction.replace
.sumber
Utas ini sangat sangat menarik dan bermanfaat.
Terima kasih Krishnabhadra untuk penjelasan dan kode Anda, saya menggunakan kode Anda dan sedikit ditingkatkan, memungkinkan untuk bertahan tumpukan, currentTab, dll ... dari perubahan konfigurasi (berputar terutama).
Diuji pada perangkat nyata 4.0.4 dan 2.3.6, tidak diuji pada emulator
Saya mengubah bagian kode ini pada "AppMainTabActivity.java", sisanya tetap sama. Mungkin Krishnabhadra akan menambahkan ini pada kodenya.
Pulihkan data onCreate:
Simpan variabel dan masukkan ke Bundel:
Jika ada CurrentTab sebelumnya, atur ini, buat Tab_A baru:
Saya harap ini membantu orang lain.
sumber
Saya akan merekomendasikan jangan menggunakan backstack berdasarkan HashMap> ada banyak bug dalam mode "jangan simpan aktivitas". Itu tidak akan benar mengembalikan keadaan jika Anda dalam tumpukan fragmen. Dan juga akan di-crack dalam fragmen peta bersarang (dengan pengecualian: Fragmen tidak ada tampilan untuk ID). Coz HashMap> setelah aplikasi latar \ foreground akan menjadi nol
Saya mengoptimalkan kode di atas untuk bekerja dengan backstack fragmen
Itu adalah TabView bagian bawah
Kegiatan utama Kelas
tags_activity.xml
<
tags_icon.xml
sumber