Agar Anda dapat lebih memahami topik fragment, akan ada beberapa codelab yang akan Anda lakukan:
- Menambahkan Fragment ke dalam Activity.
- Membuat tampilan fleksibel dengan fragment tanpa berpindah Activity.
- Mengirim data antar Fragment.
Codelab pada kali ini akan menghasilkan aplikasi seperti ini:
Logika Dasar
Melakukan klik ke button → memanggil fragment atau activity dengan atau tanpa data → menampilkan activity atau fragment yang dituju
Codelab
- Buat Project baru di Android Studio dengan kriteria sebagai berikut:
Nama Project MyFlexibleFragment Target & Minimum Target SDK Phone and Tablet, Api level 21 Tipe Activity Empty Activity Activity Name MainActivity Use AndroidX artifacts True Language Kotlin / Java - Pada activity_main.xml, silakan kondisikan kode pada berkas tersebut menjadi seperti berikut:
- <?xml version="1.0" encoding="utf-8"?>
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/frame_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- Kemudian kita buat beberapa fragment untuk mengimplementasikan perpindahan tampilan tanpa perpindahan activity. Pertama kita buat fragment dengan nama HomeFragment. Caranya : klik kanan pada package utama pada proyek aplikasi Anda → New → Fragment → Fragment (Blank).
- Setelah tampil dialog untuk fragment, isikan HomeFragment pada kolom Fragment Name dan uncheck untuk kedua pilihan (include fragment factory methods dan include interface callbacks) seperti gambar di bawah ini. Klik Finish untuk melanjutkan penciptaan fragment.
- Setelah HomeFragment tercipta, pada fragment_home.xml mari sesuaikan tampilannya dengan menambahkan sebuah objek textview dan sebuah objek button seperti berikut:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="16dp"
- android:text="@string/hello_home_fragment" />
- <Button
- android:id="@+id/btn_category"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:text="@string/to_category" />
- </LinearLayout>
Akan ada yang error pada bagian android:text .Seperti pada modul sebelumnya kita perlu menambahkan resource string-nya.
Tambahkan beberapa baris kode di bawah ini di dalam res → values → strings.xml.
- <resources>
- <string name="app_name">MyFlexibleFragment</string>
- <string name="hello_blank_fragment">Hello blank fragment</string>
- <string name="this_profile">Ini activity Profile</string>
- <string name="this_category">Ini fragment Category</string>
- <string name="category_lifestyle">Ke fragment Lifestyle</string>
- <string name="category_name">Category Name</string>
- <string name="category_description">Category Description</string>
- <string name="to_profile">Ke Halaman Profile Activity</string>
- <string name="show_dialog">Tampilkan sebuah dialog</string>
- <string name="hello_home_fragment">Hello Ini Home Fragment</string>
- <string name="to_category">Ke fragment Category</string>
- <string name="question_coach">Siapa pelatih tersukses Machester United?</string>
- <string name="sir_alex_ferguson">Sir Alex Ferguson</string>
- <string name="jose_mourinho">Jose Mourinho</string>
- <string name="louis_van_gaal">Louis Van Gaal</string>
- <string name="david_moyes">David Moyes</string>
- <string name="choose">Pilih</string>
- <string name="close">Tutup</string>
- </resources>
- Resource String ini akan kita gunakan selama latihan fragment.
- Pada HomeFragment lakukan penyesuaian kode sebagai berikut:
- class HomeFragment : Fragment(), View.OnClickListener {
- ...
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- val btnCategory:Button = view.findViewById(R.id.btn_category)
- btnCategory.setOnClickListener(this) }
- override fun onClick(v: View) {
- }
- }
- public class HomeFragment extends Fragment implements View.OnClickListener {
- ...
- @Override
- public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- Button btnCategory = view.findViewById(R.id.btn_category);
- btnCategory.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- }
- }
- Di sini kita juga siapkan kode listener onClick. Listener di sini akan kita gunakan pada latihan berikutnya.
- Selanjutnya, pada MainActivity, kita tanamkan HomeFragment ke dalam activity tersebut sehingga bisa tampil ke layar pengguna dengan menambahkan beberapa baris berikut:
- ...
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- val mFragmentManager = supportFragmentManager
- val mHomeFragment = HomeFragment()
- val fragment = mFragmentManager.findFragmentByTag(HomeFragment::class.java.simpleName)
- if (fragment !is HomeFragment) {
- Log.d("MyFlexibleFragment", "Fragment Name :" + HomeFragment::class.java.simpleName)
- mFragmentManager
- .beginTransaction()
- .add(R.id.frame_container, mHomeFragment, HomeFragment::class.java.simpleName)
- .commit()
- }
- }
- ...
- ...
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- FragmentManager mFragmentManager = getSupportFragmentManager();
- HomeFragment mHomeFragment = new HomeFragment();
- Fragment fragment = mFragmentManager.findFragmentByTag(HomeFragment.class.getSimpleName());
- if (!(fragment instanceof HomeFragment)) {
- Log.d("MyFlexibleFragment", "Fragment Name :" + HomeFragment.class.getSimpleName());
- mFragmentManager
- .beginTransaction()
- .add(R.id.frame_container, mHomeFragment, HomeFragment.class.getSimpleName())
- .commit();
- }
- }
- ...
- Setelah selesai semua, silakan jalankan aplikasi Anda. Seperti ini tampilannya.Ketika dijalankan, aplikasi akan menampilkan satu teks dan satu button yang mana kedua komponen tersebut dimiliki oleh HomeFragment.
Bedah Kode
FrameLayout
- <?xml version="1.0" encoding="utf-8"?>
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="com.dicoding.associate.myflexiblefragment.MainActivity"
- android:id="@+id/frame_container">
- </FrameLayout>
FrameLayout memiliki sifat sebagai berikut: semua komponen view di dalam framelayout bersifat menumpuk. Bila pada suatu hirarki framelayout terdapat satu view dengan posisi teratas, maka view tersebut akan menjadi alas untuk view di atasnya. Gambarannya sebagai berikut:
Dengan karakteristik seperti ini, FrameLayout merupakan sebuah layout yang paling optimal dalam proses manipulasi penampilan objek fragment ke layar pengguna.
OnCreateView
Pada HomeFragment terdapat metode onCreateView() di mana layout interface didefinisikan dan ditransformasikan dari layout berupa file xml ke dalam objek view dengan menggunakan metode inflate().
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?): View? {
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.fragment_home, container, false)
- }
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.fragment_home, container, false);
- }
OnViewCreated
Pada HomeFragment terdapat juga metode onViewCreated() yang akan bekerja setelah metode onCreateView(). Di sini kita bisa gunakan untuk inisialisasi view, dan juga mengatur action-nya (set listener).
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- val btnCategory:Button = view.findViewById(R.id.btn_category)
- btnCategory.setOnClickListener(this)
- }
- @Override
- public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- Button btnCategory = view.findViewById(R.id.btn_category);
- btnCategory.setOnClickListener(this);
- }
Catatan:
Perlu diperhatikan untuk pemanggilan findViewById() di sini tidak dapat langsung dilakukan seperti di Activity. Anda perlu menambahkan variabel view terlebih dulu di depannya sehingga menjadi view.findViewById().
Inflate di Fragment
- inflater.inflate(R.layout.fragment_home, container, false)
- inflater.inflate(R.layout.fragment_home, container, false);
Inflater.inflate() merupakan objek dari LayoutInflater yang berfungsi untuk mengubah layout xml ke dalam bentuk objek viewgroup atau widget melalui pemanggilan metode inflate().
Sama seperti setContentView pada Activity, fungsi inflate di sini yaitu untuk menampilkan layout dari Fragment, di mana layout yang ditampilkan di sini yaitu fragment_home.
- inflate(R.layout.fragment_home, container, false)
- inflate(R.layout.fragment_home, container, false);
Isian dari tiga parameter yang terdapat pada metode inflate() berdasarkan dari:
Di mana kita memilih pilihan yang ketiga :
- resource : Int : Layout yang ingin diubah
- root : ViewGroup? : Root dari Layout Activity
- attachToRoot: Boolean : Apakah kita akan menempelkan layout kita ke dalam root dari parent layout yang ada. Jika ya, maka akan ditempelkan ke dalam parent layout yang ada. Jika tidak, maka hanya akan menghasilkan nilai balik dalam bentu objek view saja.
Kita memilih false pada attachToRoot karena pada kode ini kita ingin menambahkan event onClick pada button-nya. Maka kita membutuhkan nilai balik berupa view.
Secara default, attachToRoot bernilai false. Jadi kita hanya inginkan mengubah layout xml kedalam bentuk objek view.
Bacaan berikut akan memberi wawasan yang lebih dalam tentang proses inflate sebuah layout:
findViewById di Fragment
- val btnCategory:Button = view.findViewById(R.id.btn_category)
- Button btnCategory = view.findViewById(R.id.btn_category);
Sedikit berbeda pada proses casting view dari sebuah ID di dalam layout xml, di sini casting objek button dilakukan dengan view.findViewById(R.id.btn_category).
Kode tersebut menandakan btn_category berada pada objek view di mana objek view berasal dari konversi fragment_home.xml. Bila hanya findViewById(R.id.btn_category), maka btn_category berada pada root layout, activity_main.xml.
FragmentTransaction
Sekarang pada MainActivity kita lakukan proses penempelan atau pemasangan objek HomeFragment sehingga dapat ditampilkan ke layar dengan mekanisme sebagai berikut:
- val mFragmentManager = supportFragmentManager
- val mHomeFragment = HomeFragment()
- val fragment = mFragmentManager.findFragmentByTag(HomeFragment::class.java.simpleName)
- if (fragment !is HomeFragment) {
- Log.d("MyFlexibleFragment", "Fragment Name :" + HomeFragment::class.java.simpleName)
- mFragmentManager
- .beginTransaction()
- .add(R.id.frame_container, mHomeFragment, HomeFragment::class.java.simpleName)
- .commit()
- }
- FragmentManager mFragmentManager = getSupportFragmentManager();
- HomeFragment mHomeFragment = new HomeFragment();
- Fragment fragment = mFragmentManager.findFragmentByTag(HomeFragment.class.getSimpleName());
- if (!(fragment instanceof HomeFragment)) {
- Log.d("MyFlexibleFragment", "Fragment Name :" + HomeFragment.class.getSimpleName());
- mFragmentManager
- .beginTransaction()
- .add(R.id.frame_container, mHomeFragment, HomeFragment.class.getSimpleName())
- .commit();
- }
Kita menggunakan instance dari FragmentManager yang merupakan antarmuka untuk mengorganisir objek fragment yang terdapat didalam sebuah activity.
- val mFragmentManager = supportFragmentManager
- FragmentManager mFragmentManager = getSupportFragmentManager();
FragmentTransaction merupakan fungsi untuk melakukan operasi pada fragment seperti add(), replace(), commit() dsb.
Untuk detail terkait FragmentManager, silakan Anda meluncur ke:
Untuk detail terkait FragmentManager, silakan Anda meluncur ke:
- val mHomeFragment = HomeFragment()
- val fragment = mFragmentManager.findFragmentByTag(HomeFragment::class.java.simpleName)
- if (fragment !is HomeFragment) {
- Log.d("MyFlexibleFragment", "Fragment Name :" + HomeFragment::class.java.simpleName)
- mFragmentManager
- .beginTransaction()
- .add(R.id.frame_container, mHomeFragment, HomeFragment::class.java.simpleName)
- .commit()
- }
- HomeFragment mHomeFragment = new HomeFragment();
- Fragment fragment = mFragmentManager.findFragmentByTag(HomeFragment.class.getSimpleName());
- if (!(fragment instanceof HomeFragment)) {
- Log.d("MyFlexibleFragment", "Fragment Name :" + HomeFragment.class.getSimpleName());
- mFragmentManager
- .beginTransaction()
- .add(R.id.frame_container, mHomeFragment, HomeFragment.class.getSimpleName())
- .commit();
- }
Di sinilah proses manipulasi penambahan fragment ke dalam activity terjadi. Metode .beginTransaction() untuk memulai proses perubahan. Metode add() akan menambahkan objek fragment ke dalam layout container.
Layout container ini merupakan objek framelayout dengan ID frame_container. Ia memiliki tag dengan nama kelas dari HomeFragment itu sendiri. Metode .commit() di atas akan mengeksekusi untuk melakukan pemasangan objek secara asynchronous untuk ditampilkan ke antar muka pengguna (user interface).
Selanjutnya, kita akan membuat sebuah fragment lagi untuk melihat bagaimana sebuah tampilan bisa dengan fleksibel berubah di dalam satu activity, tanpa berpindah halaman.