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.util.GeoPoint
|
||||||
import org.osmdroid.views.MapView
|
import org.osmdroid.views.MapView
|
||||||
import org.osmdroid.views.overlay.Marker
|
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() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -31,53 +41,111 @@ class MainActivity : ComponentActivity() {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OsmMapScreen() {
|
fun OsmMapScreen() {
|
||||||
// State untuk Tipe Peta (Poin 3: Switching Map Views)
|
val context = LocalContext.current
|
||||||
// Kita pakai Boolean: True = Normal, False = Topografi/Lainnya
|
val scope = rememberCoroutineScope() // Untuk menjalankan proses background (Geocoding)
|
||||||
|
|
||||||
|
// State
|
||||||
var isNormalMode by remember { mutableStateOf(true) }
|
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(
|
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 = {
|
floatingActionButton = {
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
onClick = { isNormalMode = !isNormalMode }
|
onClick = { isNormalMode = !isNormalMode }
|
||||||
) {
|
) {
|
||||||
Text(text = if (isNormalMode) "Mode Topografi" else "Mode Normal")
|
Text(text = if (isNormalMode) "Mode Topo" else "Mode Normal")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Box(modifier = Modifier.padding(paddingValues).fillMaxSize()) {
|
Box(modifier = Modifier.padding(paddingValues).fillMaxSize()) {
|
||||||
|
|
||||||
// Poin 1: Menampilkan Peta OSM menggunakan AndroidView
|
|
||||||
AndroidView(
|
AndroidView(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
factory = { context ->
|
factory = { ctx ->
|
||||||
// Inisialisasi MapView (Versi OSM)
|
MapView(ctx).apply {
|
||||||
MapView(context).apply {
|
setMultiTouchControls(true)
|
||||||
setMultiTouchControls(true) // Poin 2: Mengaktifkan Zoom dengan jari (pinch)
|
|
||||||
|
|
||||||
// Set titik awal (Contoh: Monas)
|
|
||||||
// Beda istilah: Google pakai LatLng, OSM pakai GeoPoint
|
|
||||||
val startPoint = GeoPoint(-6.175392, 106.827153)
|
val startPoint = GeoPoint(-6.175392, 106.827153)
|
||||||
controller.setZoom(18.0) // Level zoom
|
controller.setZoom(18.0)
|
||||||
controller.setCenter(startPoint)
|
controller.setCenter(startPoint)
|
||||||
|
|
||||||
// Tambahkan Marker sederhana
|
// --- LOGIKA SENTUH PETA (Poin 4) ---
|
||||||
val marker = Marker(this)
|
val eventReceiver = object : MapEventsReceiver {
|
||||||
marker.position = startPoint
|
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.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
|
||||||
marker.title = "Monas"
|
marker.title = "Lokasi Dipilih"
|
||||||
overlays.add(marker)
|
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 ->
|
update = { view ->
|
||||||
// Kode disini dijalankan setiap kali ada perubahan State (isNormalMode berubah)
|
|
||||||
|
|
||||||
// Poin 3: Logika ganti tipe peta
|
|
||||||
if (isNormalMode) {
|
if (isNormalMode) {
|
||||||
view.setTileSource(TileSourceFactory.MAPNIK) // Tampilan Standar OSM
|
view.setTileSource(TileSourceFactory.MAPNIK)
|
||||||
} else {
|
} else {
|
||||||
view.setTileSource(TileSourceFactory.USGS_TOPO) // Tampilan Topografi (Gratis)
|
view.setTileSource(TileSourceFactory.USGS_TOPO)
|
||||||
// Catatan: OSM tidak punya satelit gratis yang sebagus Google,
|
|
||||||
// jadi kita pakai Topo atau Public Transport sebagai alternatif tampilan.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user