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 } } }