Google Map integration with Movable Marker using kotlin
Creating the layout for showing map
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<fragment
android:id="@+id/map"
android:layout_below="@id/checkInToolbar"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
Functionality for showing map with movable marker
companion object {
const val LOCATION_PERMISSION_REQUEST_CODE = 1
const val REQUEST_CHECK_SETTINGS = 2
}
var address=""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mapsBinding=ActivityGoogleMapsBinding.inflate(layoutInflater)
sharedPreference = SharedPreference(this)
setContentView(mapsBinding.root)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
// fetchLocation()
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
locationCallback = object : LocationCallback() {
override fun onLocationResult(p0: LocationResult){
super.onLocationResult(p0)
lastLocation = p0.lastLocation!!
placeMarkerOnMap(LatLng(lastLocation.latitude, lastLocation.longitude))
}
}
createLocationRequest()
}
internal fun placeMarkerOnMap(location: LatLng) {
val markerOptions = MarkerOptions().position(location)
marker?.remove()
marker = mMap.addMarker(markerOptions)
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(location, 20f))
// Log.d("TAG", "placeMarkerOnMap: $marker")
@SuppressLint("LogConditional", "SetTextI18n")
internal fun placeMarkerAtCurrentLocation(){
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fusedLocationClient!!.lastLocation.addOnSuccessListener { location: Location? ->
location?.let {
val latLng = LatLng(it.latitude, it.longitude)
val markerOptions = MarkerOptions().position(latLng).title("My Location").draggable(true)
marker = mMap.addMarker(markerOptions)
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 20f)) // Zoom level can be adjusted
}
}
.addOnFailureListener { e ->
// Handle failure to get location
}
} else {
// Request location permission if not granted
// Handle the permission request, typically by using ActivityCompat.requestPermissions()
}
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
mMap.setOnMarkerClickListener(this)
mMap.setOnCameraIdleListener(this)
setUpMap()
placeMarkerAtCurrentLocation()
}
override fun onCameraIdle() {
// Fetch the location details when the map camera stops moving
val cameraPosition = mMap.cameraPosition.target
fetchLocationDetails(cameraPosition)
updateMarkerPosition(cameraPosition)
}
internal fun updateMarkerPosition(latLng: LatLng) {
// marker?.position = latLng
if (marker == null) {
// Create a new marker if it doesn't exist
val markerOptions = MarkerOptions().position(latLng)
marker = mMap.addMarker(markerOptions)
} else {
// Animate the marker to the new position
val currentLatLng = marker!!.position
val startPosition = currentLatLng.latitude to currentLatLng.longitude
val endPosition = latLng.latitude to latLng.longitude
val valueAnimator = ValueAnimator.ofFloat(0f, 1f)
valueAnimator.duration = 100 // Animation duration in milliseconds
valueAnimator.addUpdateListener { animation ->
val fraction = animation.animatedFraction
val newPosition = LatLng(
startPosition.first + fraction * (endPosition.first - startPosition.first),
startPosition.second + fraction * (endPosition.second - startPosition.second)
)
marker!!.position = newPosition
}
valueAnimator.start()
}
}
private fun fetchLocationDetails(latLng: LatLng) {
try {
val geocoder = Geocoder(this, Locale.getDefault())
val addresses = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1)
if (addresses!!.isNotEmpty()) {
address = addresses[0].getAddressLine(0)
val locationDetails = "${latLng.latitude} ${latLng.longitude}"
mapsBinding.edtLocation.setText(locationDetails)
mapsBinding.location.setOnClickListener {
sharedPreference.save("latlong",locationDetails)
val i = Intent(this@GoogleMapsActivity, BusinessdetailsActivity::class.java)
startActivity(i)
}
}
} catch (e: IOException) {
e.printStackTrace()
// Handle any errors that occur during geocoding, such as network issues.
}
}
private fun setUpMap() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
mMap.isMyLocationEnabled = true
} else {
// Request location permission if not granted
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
LOCATION_PERMISSION_REQUEST_CODE
)
}
}
private fun createLocationRequest() {
locationRequest = LocationRequest()
locationRequest.interval = 10000
locationRequest.fastestInterval = 5000
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest)
// 4
val client = LocationServices.getSettingsClient(this)
val task = client.checkLocationSettings(builder.build())
// 5
task.addOnSuccessListener {
locationUpdateState = true
startLocationUpdates()
}
task.addOnFailureListener { e ->
if (e is ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
e.startResolutionForResult(
this,
REQUEST_CHECK_SETTINGS
)
} catch (sendEx: IntentSender.SendIntentException) {
// Ignore the error.
}
}
}
}
override fun onMarkerClick(p0: Marker): Boolean = false
@Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CHECK_SETTINGS) {
if (resultCode == Activity.RESULT_OK) {
locationUpdateState = true
}
}
}