Android Kotlin #8: Detail Screen – Berpindah Halaman dan Mengirim Data
Halo lagi, calon developer aplikasi wisata!
Di artikel sebelumnya kita sudah bisa menampilkan daftar tempat wisata dengan gambar. Tapi kalau diklik, cuma muncul Toast. Pasti penggemar wisata penasaran dong dengan detail lengkapnya? Nah, di artikel ini kita akan buat halaman detail yang muncul saat item diklik. Kita akan belajar pindah halaman (activity baru), mengirim data via Intent, dan menampilkan informasi lengkap tempat wisata.
Alur yang Akan Kita Buat
- Pengguna klik salah satu item di daftar wisata (RecyclerView).
- Aplikasi membuka DetailActivity yang baru.
- Data tempat wisata yang diklik dikirim melalui Intent.
- DetailActivity menerima data dan menampilkannya di layout yang lebih besar.
- Ada tombol kembali (back) untuk kembali ke daftar.
Langkah 1: Membuat Activity Baru (DetailActivity)
Klik kanan pada package com.example.wisataapp → New → Activity → Empty Views Activity (atau Empty Activity).
- Name:
DetailActivity - Layout Name:
activity_detail(otomatis) - Language: Kotlin
- Klik Finish.
Android Studio akan membuat file DetailActivity.kt dan activity_detail.xml.
Langkah 2: Mendesain Layout Detail (activity_detail.xml)
Buka activity_detail.xml. Kita akan buat tampilan yang menampilkan gambar besar, nama, lokasi, deskripsi, dan harga tiket. Gunakan ScrollView agar bisa digulir kalau kontennya panjang.
Berikut contoh layout sederhana (bisa dikembangkan sendiri):
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<ImageView
android:id="@+id/imageDetail"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:src="@drawable/placeholder_image"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textNama"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Nama Wisata"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/imageDetail" />
<TextView
android:id="@+id/textLokasi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Lokasi"
android:textSize="18sp"
android:textColor="@android:color/darker_gray"
app:layout_constraintTop_toBottomOf="@id/textNama" />
<TextView
android:id="@+id/textHarga"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Harga Tiket"
android:textSize="20sp"
android:textColor="@android:color/holo_green_dark"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/textLokasi" />
<TextView
android:id="@+id/textDeskripsi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Deskripsi lengkap tempat wisata akan ditampilkan di sini. Bisa sangat panjang sehingga perlu ScrollView."
android:textSize="16sp"
app:layout_constraintTop_toBottomOf="@id/textHarga" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
Jangan lupa ganti @drawable/placeholder_image dengan gambar placeholder yang sudah dibuat.
Langkah 3: Mengirim Data dengan Intent (Parcelable)
Untuk mengirim objek kompleks (seperti DaftarWisata) antar Activity, kita perlu membuatnya Parcelable (atau Serializable, tapi Parcelable lebih cepat).
Kita akan mengubah DaftarWisata menjadi Parcelable. Cara termudah: gunakan plugin Kotlin @Parcelize. Pastikan di build.gradle (Module: app) sudah ada plugin kotlin-parcelize:
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-parcelize' // 👈 tambahkan ini
}
Sync project. Kemudian ubah DaftarWisata.kt menjadi:
package com.example.wisataapp
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class DaftarWisata(
val id: Int,
val nama: String,
val deskripsi: String?,
val lokasi: String?,
val hargaTiket: Double?,
val kategoriId: Int,
val imagePath: String?
) : Parcelable
Tambahkan juga @Parcelize pada KategoriWisata jika diperlukan nanti.
Langkah 4: Memodifikasi WisataAdapter untuk Membuka DetailActivity
Di WisataAdapter.kt, kita sudah punya parameter onItemClick yang dipanggil saat item diklik. Sekarang kita akan mengubahnya dari MainActivity agar membuka DetailActivity.
Di MainActivity.kt, saat membuat adapter, kita ubah listener-nya:
adapter = WisataAdapter(listWisata) { wisata ->
// Intent ke DetailActivity
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("wisata", wisata) // mengirim objek Parcelable
startActivity(intent)
}
Jangan lupa import android.content.Intent.
Langkah 5: Menerima Data di DetailActivity
Buka DetailActivity.kt. Di dalam onCreate, kita ambil data dari Intent:
package com.example.wisataapp
import android.os.Bundle
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
class DetailActivity : AppCompatActivity() {
private lateinit var imageDetail: ImageView
private lateinit var textNama: TextView
private lateinit var textLokasi: TextView
private lateinit var textHarga: TextView
private lateinit var textDeskripsi: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
// Inisialisasi view
imageDetail = findViewById(R.id.imageDetail)
textNama = findViewById(R.id.textNama)
textLokasi = findViewById(R.id.textLokasi)
textHarga = findViewById(R.id.textHarga)
textDeskripsi = findViewById(R.id.textDeskripsi)
// Ambil data dari Intent
val wisata = intent.getParcelableExtra<DaftarWisata>("wisata")
if (wisata != null) {
// Tampilkan data
textNama.text = wisata.nama
textLokasi.text = wisata.lokasi ?: "Lokasi tidak diketahui"
textHarga.text = if (wisata.hargaTiket != null)
"Rp ${wisata.hargaTiket}" else "Gratis"
textDeskripsi.text = wisata.deskripsi ?: "Tidak ada deskripsi"
// Load gambar dengan Glide (gunakan gambar besar, misal dengan transformasi)
Glide.with(this)
.load(wisata.imagePath) // pastikan URL lengkap
.placeholder(R.drawable.placeholder_image)
.error(R.drawable.error_image)
.transform(CenterCrop(), RoundedCorners(16))
.into(imageDetail)
} else {
// Jika data tidak ada, mungkin error
textNama.text = "Data tidak ditemukan"
}
}
}
Langkah 6: Menambahkan Tombol Kembali (Up Navigation)
Agar pengguna bisa kembali ke daftar dengan mudah, kita bisa mengaktifkan tombol back di action bar (panah kiri). Di DetailActivity.kt, tambahkan di onCreate:
supportActionBar?.setDisplayHomeAsUpEnabled(true)
Dan override method onSupportNavigateUp:
override fun onSupportNavigateUp(): Boolean {
onBackPressedDispatcher.onBackPressed()
return true
}
Atau lebih sederhana: dengan menambahkan android:parentActivityName di AndroidManifest.xml. Tapi untuk sementara, back button di HP sudah cukup.
Langkah 7: Menambahkan Toolbar (Opsional)
Jika ingin action bar yang lebih kustom, bisa gunakan Toolbar. Tapi untuk sederhana, kita pakai action bar bawaan.
Langkah 8: Jalankan Aplikasi
Pastikan API berjalan. Buka aplikasi, klik salah satu item di daftar wisata. Maka akan terbuka halaman detail dengan informasi lengkap dan gambar besar. Kembali dengan menekan tombol back di pojok kiri atas atau tombol fisik back.
wisata.imagePath langsung, padahal di API biasanya hanya path relatif. Jadi kita perlu menggabungkan dengan base URL. Contoh: "http://10.0.2.2:7000${wisata.imagePath}".
Mengatasi URL Gambar Relatif
Jika imagePath dari API hanya berisi /uploads/gambar.jpg, maka kita harus menambahkan base URL saat load gambar. Di DetailActivity, ubah menjadi:
val baseUrl = "http://10.0.2.2:7000" // atau dari resource
Glide.with(this)
.load(baseUrl + wisata.imagePath)
...
Atau lebih baik, buat fungsi extension atau simpan base URL di object RetrofitInstance.
Selamat! Sekarang Aplikasi Punya Halaman Detail
Dengan fitur ini, aplikasi wisata kamu sudah layak disebut aplikasi sungguhan. Pengguna bisa melihat informasi lengkap setiap tempat wisata.
Rangkuman
- Intent: digunakan untuk berpindah antar activity.
- putExtra: mengirim data (primitif, Parcelable, Serializable).
- Parcelable: cara efisien mengirim objek, mudah dengan
@Parcelize. - getParcelableExtra: mengambil objek Parcelable dari intent.
- Glide: tetap digunakan di halaman detail untuk memuat gambar besar.
Selanjutnya?
Di artikel berikutnya (Android Kotlin #9: ViewModel dan LiveData – Arsitektur Modern), kita akan merapikan kode dengan memisahkan logika dari Activity menggunakan ViewModel dan LiveData. Ini penting untuk menghindari kebocoran memori dan mempertahankan data saat rotasi layar. Sampai jumpa!
Ditulis oleh Kakak programmer yang dulu juga sering lupa nambah base URL gambar. Kalau ada pertanyaan, tulis di komentar ya!