Open In App

How to Add Uber Car Animation in Android App?

Improve
Improve
Like Article
Like
Save
Share
Report

Google Map is being used in a lot of applications these days. Many apps need google maps services for multiple purposes. Example of such apps is our daily life applications like Zomato, Swiggy and amazon uses google maps for delivery purposes while apps like uber and ola use maps for tracking the real-time location of the passenger and driver, In all of the examples above its been seen that various types of animations appear on mapping lines like in uber a car is shown for tracking the location of the driver and is displayed on the customer screen, In this article, we are going see how to add those animations in android with google maps.

  • Getting started with Google Maps Platform
  • Integrating google maps with android
  • Adding Animations in Maps

Getting started with the Google Maps Platform

Step 1: Go to https://console.developers.google.com/ and click on the project dropdown button and select a project or create one.

Step 2: Click on the menu button which is on the upper left side of the website, then select APIs and services after that another dropdown list will appear, from that select the credentials.

Step 3: Once you are on the credentials page click on the “Create credentials” button then click on the API key then a pop-up will appear displaying the API key. Make sure you copy and paste the API key in notepad or something like that.

Step 4: Now come back to API and services tab and click on the “Library” button then search for google map SDK for android then click on enable.

Integrating google maps with android

Step 1: Create a new project 

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.

Step 2: Update Android Manifest file

Go to the AndroidManifests.xml file and add the following code inside the <application> tag. Remember we copied the API key, make sure to paste it below as shown below.

XML




<application>
    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="API_KEY" />
</application>


Step 3: Adding Google maps fragment in activity_main.xml file

We will add the google map fragment inside which the map will be displayed. Remove all the code in activity_main.xml before adding the code below

XML




<?xml version="1.0" encoding="utf-8"?>
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" />


Step 4: Setting Up google map in MainActivity file

Just define the Google Map fragment and implement the OnMapReadyCallBack interface and override the onMapReady() function as below

Kotlin




class MainActivity : AppCompatActivity(), OnMapReadyCallback {
  
    private lateinit var googleMap: GoogleMap
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val map = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        map.getMapAsync(this)
    }
  
    override fun onMapReady(googleMap: GoogleMap) {
        this.googleMap = googleMap
    }


Step 5: Show default location on Map

By default, the map can show any random position but we can show the location as we please. In this project, we will be using LatLng(28.435350000000003, 77.11368) location as the default location, when the app starts. So, we need to make two functions moveCamera() and animateCamera(). The moveCamera() method, will be used to reposition the camera to some latitude and longitude. While the animateCamera() method will be used to animate the movement of the camera from the current position to some new position. 

Kotlin




private fun moveView(ll: LatLng) {
       googleMap.moveCamera(CameraUpdateFactory.newLatLng(ll))
   }
 
   private fun animateView(ll: LatLng) {
       val cameraPosition = CameraPosition.Builder().target(ll).zoom(15.5f).build()
       googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
   }


Make another function showDefaultLocaitonOnMap() and call it inside onMapReady().

private fun displayDefaultLocation(ll: LatLng) {
        moveView(ll)
        animateView(ll)
  }

Kotlin




private lateinit var defaultLocation: LatLng
  
override fun onMapReady(googleMap: GoogleMap) {
    this.googleMap = googleMap
    defaultLoc = LatLng(28.435350000000003, 77.11368)
    displayDefaultLocation(defaultLoc)
}


Step 6: Creating Utils

Create two new Kotlin object files, 

  • MapUtils.kt 
  • AnimationUtils.kt

Step 7: Working with MapUtils file

In our project, we will be using some hard-coded values of LatLng. So, in the MapUtils class, let’s create a function getLocations() that will return a list of LatLng that will correspond to a path.

Kotlin




fun getLocations(): ArrayList<LatLng> {
       val locationList = ArrayList<LatLng>()
       locationList.add(LatLng(28.4356, 77.11498))
       locationList.add(LatLng(28.435660000000002, 77.11519000000001))
       locationList.add(LatLng(28.43568, 77.11521))
       locationList.add(LatLng(28.436580000000003, 77.11499))
       locationList.add(LatLng(28.436590000000002, 77.11507))
       locationList.add(LatLng(28.436970000000002, 77.11272000000001))
       locationList.add(LatLng(28.43635, 77.11289000000001))
       locationList.add(LatLng(28.4353, 77.11317000000001))
       locationList.add(LatLng(28.435280000000002, 77.11332))
       locationList.add(LatLng(28.435350000000003, 77.11368))
       return locationList
   }


Now, we have a list of LatLng and with the help of the LatLng, we can draw a path between the Origin and the Destination. Now we will create a function getStartingLocationBitmap() which will return a Bitmap. The function will be as below

Kotlin




fun getStartingLocationBitmap(): Bitmap {
       val height = 40
       val width = 40
       val bitmap = Bitmap.createBitmap(height, width, Bitmap.Config.RGB_565)
       val canvas = Canvas(bitmap)
       val paint = Paint()
       paint.color = Color.BLACK
       paint.style = Paint.Style.FILL
       paint.isAntiAlias = true
       canvas.drawRect(0F, 0F, width.toFloat(), height.toFloat(), paint)
       return bitmap
   }


Now create a new function named getCarRotation() which takes two locations i.e. start and end and then returns the angle between them, from the angle it will return we will determine how the car icon should be directed.

Kotlin




fun getCarRotation(startLL: LatLng, endLL: LatLng): Float {
       val latDifference: Double = abs(startLL.latitude - endLL.latitude)
       val lngDifference: Double = abs(startLL.longitude - endLL.longitude)
       var rotation = -1F
       when {
           startLL.latitude < endLL.latitude && startLL.longitude < endLL.longitude -> {
               rotation = Math.toDegrees(atan(lngDifference / latDifference)).toFloat()
           }
           startLL.latitude >= endLL.latitude && startLL.longitude < endLL.longitude -> {
               rotation = (90 - Math.toDegrees(atan(lngDifference / latDifference)) + 90).toFloat()
           }
           startLL.latitude >= endLL.latitude && startLL.longitude >= endLL.longitude -> {
               rotation = (Math.toDegrees(atan(lngDifference / latDifference)) + 180).toFloat()
           }
           startLL.latitude < endLL.latitude && startLL.longitude >= endLL.longitude -> {
               rotation =
                   (90 - Math.toDegrees(atan(lngDifference / latDifference)) + 270).toFloat()
           }
       }
       return rotation
   }


Every function mentioned above will go inside the MapUtils file.

Step 8: Working with AnimationUtils file

Create two functions polyAnimator() and carAnimator which will return an interpolator value as shown below

Kotlin




fun polyAnimator(): ValueAnimator {
        val valueAnimator = ValueAnimator.ofInt(0, 100)
        valueAnimator.interpolator = LinearInterpolator()
        valueAnimator.duration = 4000
        return valueAnimator
    }
  
    fun carAnimator(): ValueAnimator {
        val valueAnimator = ValueAnimator.ofFloat(0f, 1f)
        valueAnimator.duration = 3000
        valueAnimator.interpolator = LinearInterpolator()
        return valueAnimator
    }


Step 9: Working with MainActivity

Create two new functions getCarMarker() and getOrigonMarker() Who will return a marker object, it will be used in Update car location. Create the functions as shown below

Kotlin




private fun getCarMarker(ll: LatLng): Marker {
     val bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(MapUtils.getBitmap(this))
     return googleMap.addMarker(
         MarkerOptions().position(ll).flat(true).icon(bitmapDescriptor)
     )
 }
 
 private fun getOriginMarker(ll: LatLng): Marker {
     val bitmapDescriptor =
         BitmapDescriptorFactory.fromBitmap(MapUtils.getStartingLocationBitmap())
     return googleMap.addMarker(
         MarkerOptions().position(ll).flat(true).icon(bitmapDescriptor)
     )
 }


Now create a function named displayPath() that will take a list of LatLng and this function will be used to draw a path between origin and destination.

Kotlin




private fun displayPath(latLngList: ArrayList<LatLng>) {
        val builder = LatLngBounds.Builder()
        for (latLng in latLngList) {
            builder.include(latLng)
        }
        val boundBuilds = builder.build()
        googleMap.animateCamera(CameraUpdateFactory.newLatLngBounds(boundBuilds, 2))
  
        val polyOptions = PolylineOptions()
        polyOptions.color(Color.GRAY)
        polyOptions.width(5f)
        polyOptions.addAll(latLngList)
        greyLine = googleMap.addPolyline(polyOptions)
  
        val blackPolyOptions = PolylineOptions()
        blackPolyOptions.color(Color.BLACK)
        blackPolyOptions.width(5f)
        blackLine = googleMap.addPolyline(blackPolyOptions)
  
        oMarker = getOriginMarker(latLngList[0])
        oMarker?.setAnchor(0.5f, 0.5f)
        dMarker = getOriginMarker(latLngList[latLngList.size - 1])
        dMarker?.setAnchor(0.5f, 0.5f)
  
        val polyAnimator = AnimationUtils.polyAnimator()
        polyAnimator.addUpdateListener { valueAnimator ->
            val precent = (valueAnimator.animatedValue as Int)
            val indexNumber = (greyLine?.points!!.size) * (precent / 100.0f).toInt()
            blackLine?.points = greyLine?.points!!.subList(0, indexNumber)
        }
        polyAnimator.start()
    }


Create function updateCarLoc() which will check if the car is moving or not and if the car is not moving already then this function will make the car move.

Kotlin




private fun updateCarLoc(ll: LatLng) {
        if (movingMarker == null) {
            movingMarker = getCarMarker(ll)
        }
        if (previousLL == null) {
            currentLL = ll
            previousLL = currentLL
            movingMarker?.position = currentLL
            movingMarker?.setAnchor(0.5f, 0.5f)
            animateView(currentLL!!)
        } else {
            previousLL = currentLL
            currentLL = ll
            val valueAnimator = AnimationUtils.carAnimator()
            valueAnimator.addUpdateListener { va ->
                if (currentLL != null && previousLL != null) {
                    val multiplier = va.animatedFraction
                    val nxtLoc = LatLng(
                        multiplier * currentLL!!.latitude + (1 - multiplier) * previousLL!!.latitude,
                        multiplier * currentLL!!.longitude + (1 - multiplier) * previousLL!!.longitude
                    )
                    movingMarker?.position = nxtLoc
                    val rotation = MapUtils.getCarRotation(previousLL!!, nxtLoc)
                    if (!rotation.isNaN()) {
                        movingMarker?.rotation = rotation
                    }
                    movingMarker?.setAnchor(0.5f, 0.5f)
                    animateView(nxtLoc)
                }
            }
            valueAnimator.start()
        }
    }


Finally, create function displayMovingCar() inside which we will call updateCarLoc() until the endpoint of location. We will also use a handler to show a delay.

Kotlin




private fun displayMovingCar(cabLatLngList: ArrayList<LatLng>) {
       myHandler = Handler()
       var index = 0
       myRunnable = Runnable {
           run {
               if (index < 10) {
                   updateCarLoc(cabLatLngList[index])
                   myHandler.postDelayed(myRunnable, 3000)
                   ++index
               } else {
                   myHandler.removeCallbacks(myRunnable)
                   Toast.makeText(this@MainActivity, "Trip Ends", Toast.LENGTH_LONG).show()
               }
           }
       }
       myHandler.postDelayed(myRunnable, 5000)
   }


Output: 

In the output, we can see a moving car from one to another point.

Output



Last Updated : 25 Feb, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads