Klik Peta & Ambil Lokasi, Geocoding/Reverse Geocoding untuk mendapat alamat
This commit is contained in:
parent
a5b122d4e8
commit
575162379f
@ -14,6 +14,16 @@ import org.osmdroid.tileprovider.tilesource.TileSourceFactory
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import org.osmdroid.views.MapView
|
||||
import org.osmdroid.views.overlay.Marker
|
||||
import android.location.Geocoder
|
||||
import android.widget.Toast
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.osmdroid.events.MapEventsReceiver
|
||||
import org.osmdroid.views.overlay.MapEventsOverlay
|
||||
import java.util.Locale
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -31,53 +41,111 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
@Composable
|
||||
fun OsmMapScreen() {
|
||||
// State untuk Tipe Peta (Poin 3: Switching Map Views)
|
||||
// Kita pakai Boolean: True = Normal, False = Topografi/Lainnya
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope() // Untuk menjalankan proses background (Geocoding)
|
||||
|
||||
// State
|
||||
var isNormalMode by remember { mutableStateOf(true) }
|
||||
var selectedAddress by remember { mutableStateOf("Sentuh peta untuk cari alamat...") }
|
||||
|
||||
// Kita simpan referensi MapView agar bisa dimanipulasi (tambah marker) dari luar AndroidView
|
||||
var mapViewRef by remember { mutableStateOf<MapView?>(null) }
|
||||
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
// Menampilkan Alamat Hasil Geocoding
|
||||
Surface(
|
||||
shadowElevation = 8.dp,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
text = selectedAddress,
|
||||
modifier = Modifier.padding(16.dp),
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
)
|
||||
}
|
||||
},
|
||||
floatingActionButton = {
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = { isNormalMode = !isNormalMode }
|
||||
) {
|
||||
Text(text = if (isNormalMode) "Mode Topografi" else "Mode Normal")
|
||||
Text(text = if (isNormalMode) "Mode Topo" else "Mode Normal")
|
||||
}
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(modifier = Modifier.padding(paddingValues).fillMaxSize()) {
|
||||
|
||||
// Poin 1: Menampilkan Peta OSM menggunakan AndroidView
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
factory = { context ->
|
||||
// Inisialisasi MapView (Versi OSM)
|
||||
MapView(context).apply {
|
||||
setMultiTouchControls(true) // Poin 2: Mengaktifkan Zoom dengan jari (pinch)
|
||||
|
||||
// Set titik awal (Contoh: Monas)
|
||||
// Beda istilah: Google pakai LatLng, OSM pakai GeoPoint
|
||||
factory = { ctx ->
|
||||
MapView(ctx).apply {
|
||||
setMultiTouchControls(true)
|
||||
val startPoint = GeoPoint(-6.175392, 106.827153)
|
||||
controller.setZoom(18.0) // Level zoom
|
||||
controller.setZoom(18.0)
|
||||
controller.setCenter(startPoint)
|
||||
|
||||
// Tambahkan Marker sederhana
|
||||
val marker = Marker(this)
|
||||
marker.position = startPoint
|
||||
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
|
||||
marker.title = "Monas"
|
||||
overlays.add(marker)
|
||||
// --- LOGIKA SENTUH PETA (Poin 4) ---
|
||||
val eventReceiver = object : MapEventsReceiver {
|
||||
override fun singleTapConfirmedHelper(p: GeoPoint): Boolean {
|
||||
// 1. Hapus marker lama (opsional, biar tidak penuh)
|
||||
overlays.clear()
|
||||
// Jangan lupa tambahkan ulang event overlay ini agar bisa diklik lagi
|
||||
val eventsOverlay = MapEventsOverlay(this)
|
||||
overlays.add(eventsOverlay)
|
||||
|
||||
// 2. Tambah Marker Baru di titik sentuh
|
||||
val marker = Marker(this@apply)
|
||||
marker.position = p
|
||||
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
|
||||
marker.title = "Lokasi Dipilih"
|
||||
overlays.add(marker)
|
||||
invalidate() // Refresh peta
|
||||
|
||||
// 3. Lakukan Geocoding (Poin 5)
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val geocoder = Geocoder(ctx, Locale.getDefault())
|
||||
// Ambil max 1 hasil alamat
|
||||
val addresses = geocoder.getFromLocation(p.latitude, p.longitude, 1)
|
||||
|
||||
val resultText = if (!addresses.isNullOrEmpty()) {
|
||||
val address = addresses[0]
|
||||
// Gabungkan baris alamat (misal: Jl. Sudirman, Jakarta)
|
||||
address.getAddressLine(0)
|
||||
} else {
|
||||
"Alamat tidak ditemukan"
|
||||
}
|
||||
|
||||
// Update UI harus di Main Thread
|
||||
withContext(Dispatchers.Main) {
|
||||
selectedAddress = resultText
|
||||
marker.snippet = resultText
|
||||
marker.showInfoWindow() // Tampilkan balon info otomatis
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
selectedAddress = "Error: Cek koneksi internet"
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun longPressHelper(p: GeoPoint?): Boolean = false
|
||||
}
|
||||
|
||||
// Pasang "jaring" penangkap sentuhan ke peta
|
||||
val eventsOverlay = MapEventsOverlay(eventReceiver)
|
||||
overlays.add(eventsOverlay)
|
||||
|
||||
mapViewRef = this
|
||||
}
|
||||
},
|
||||
update = { view ->
|
||||
// Kode disini dijalankan setiap kali ada perubahan State (isNormalMode berubah)
|
||||
|
||||
// Poin 3: Logika ganti tipe peta
|
||||
if (isNormalMode) {
|
||||
view.setTileSource(TileSourceFactory.MAPNIK) // Tampilan Standar OSM
|
||||
view.setTileSource(TileSourceFactory.MAPNIK)
|
||||
} else {
|
||||
view.setTileSource(TileSourceFactory.USGS_TOPO) // Tampilan Topografi (Gratis)
|
||||
// Catatan: OSM tidak punya satelit gratis yang sebagus Google,
|
||||
// jadi kita pakai Topo atau Public Transport sebagai alternatif tampilan.
|
||||
view.setTileSource(TileSourceFactory.USGS_TOPO)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user