Now we have a simple map with a floor selector where you can search for locations. When finishing this step you'll be able to create a directions between two points and change the transportation mode.
After having created our list of search results, we have a good starting point for creating directions between two Locations. Since our search only supports a single search, we will hardcode a Location's coordinate into our app, and use that as the basis for our Origin. Then we'll create a route, navigate to a view of the navigation details, and show a route on the map from the Origin to the Destination.
We have already created a point in the basic example, called mUserLocation to use as a starting point for directions on MapsActivity
var mUserLocation: MPPoint=MPPoint(38.897389429704695, -77.03740973527613,0)
Now we will create a method that can generate a route for us with a Location (picked from the search list). Start by implementing OnRouteResultListener to your MapsActivity.
Implement the onRouteResult method and create a method called createRoute(MPLocation mpLocation) on your MapsActivity.
Use this method to query the MPDirectionsService, which generates a route between two coordinates. We will use this to query a route with our hardcoded mUserLocation and a point from a MPLocation.
To generate a route with the MPLocation, we start by creating an onClickListener on our search ViewHolder inside the SearchItemAdapter. In the method onBindViewHolder we will call our createRoute on the MapsActivity for our route to be generated.
overridefunonBindViewHolder(holder: ViewHolder, position: Int) {... holder.itemView.setOnClickListener { mLocations[position]?.let { locations -> mMapActivity?.createRoute(locations) }//Clearing map to remove the location filter from our search result mMapActivity?.getMapControl()?.clearFilter() }...}
We start by implementing logic to our createRoute method to query a route through MPDirectionsService and assign the onRouteResultListener to the activity. When we call the createRoute through our onClickListener we will receive a result through our onRouteResult implementation.
When we receive a result on our listener, we render the route through the MPDirectionsRenderer.
funcreateRoute(mpLocation: MPLocation) {//If MPRoutingProvider has not been instantiated create it here and assign the results call back to the activity.if (mpRoutingProvider ==null) { mpRoutingProvider =MPDirectionsService(this) mpRoutingProvider?.setRouteResultListener(this) }//Queries the MPRouting provider for a route with the hardcoded user location and the point from a location. mpRoutingProvider?.query(mUserLocation, mpLocation.point)}overridefunonRouteResult(@Nullable route: Route?, @Nullable miError: MIError?) {...//Create the MPDirectionsRenderer if it has not been instantiated.if (mpDirectionsRenderer ==null) { mpDirectionsRenderer =MPDirectionsRenderer(mMapControl) }//Set the route on the Directions renderer mpDirectionsRenderer?.setRoute(route)//Create a new instance of the navigation fragment mNavigationFragment = NavigationFragment.newInstance(route, this)//Start a transaction and assign it to the BottomSheetaddFragmentToBottomSheet(mNavigationFragment)}
See the full implementation of these methods here: MapsActivity.kt
Now we will implement logic to our NavigationFragment that we can put into our BottomSheet and show the steps for each route, as well as the time and distance it takes to travel the route.
Here we'll use a viewpager to allow the user to switch between each step, as well as display a "close" button so we are able to remove the route and the bottom sheet from the activity.
We will start by making a getter for our MPdirectionsRenderer that we store on MapsActivity:
classNavigationFragment : Fragment() {privatevar mRoute: MPRoute? =nullprivatevar mMapsActivity: MapsActivity? =null...overridefunonViewCreated(view: View, @Nullable savedInstanceState: Bundle?) {val routeCollectionAdapter =RouteCollectionAdapter(this)val mViewPager: ViewPager2= view.findViewById(R.id.view_pager) mViewPager.adapter = routeCollectionAdapter mViewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {overridefunonPageSelected(position: Int) {super.onPageSelected(position)//When a page is selected call the renderer with the index mMapsActivity?.getMpDirectionsRenderer()?.selectLegIndex(position)//Update the floor on mapcontrol if the floor might have changed for the routing mMapsActivity?.getMpDirectionsRenderer()?.selectedLegFloorIndex?.let {floorIndex -> mMapsActivity?.getMapControl()?.selectFloor(floorIndex) } } })...//Button for closing the bottom sheet. Clears the route through directionsRenderer as well, and changes map padding. closeBtn.setOnClickListener { mMapsActivity!!.removeFragmentFromBottomSheet(this) mMapsActivity!!.getMpDirectionsRenderer()?.clear() }//Next button for going through the legs of the route. nextBtn.setOnClickListener { mViewPager.setCurrentItem( mViewPager.currentItem +1,true ) }//Back button for going through the legs of the route. backBtn.setOnClickListener { mViewPager.setCurrentItem( mViewPager.currentItem -1,true ) }//Describing the distance in meters distanceTxtView.text ="Distance: "+ mRoute?.getDistance().toString() +" m"//Describing the time it takes for the route in minutes infoTxtView.text ="Time for route: "+ mRoute?.duration?.toLong()?.let {duration -> TimeUnit.MINUTES.convert(duration, TimeUnit.SECONDS).toString() } +" minutes" }innerclassRouteCollectionAdapter(fragment: Fragment?) :... }companionobject {funnewInstance(route: Route?, mapsActivity: MapsActivity?): NavigationFragment {val fragment =NavigationFragment() fragment.mRoute = route fragment.mMapsActivity = mapsActivityreturn fragment } }}
See the full implementation of NavigationFragment and the accompanying adapter here: NavigationFragment.kt
We will then create a simple textview to describe each step of the Route Leg in the RouteLegFragment for the ViewPager:
In MapsIndoors, the transportation mode is referred to as travel mode. There are four travel modes, walking, bicycling, driving and transit (public transportation). The travel modes generally applies for outdoor navigation. Indoor navigation calculations are based on walking travel mode.
To swap Travel Modes you set the Travel Mode before making a query for the route:
funcreateRoute(mpLocation: MPLocation) {//If MPDirectionsService has not been instantiated create it here and assign the results call back to the activity.if (mpDirectionsService ==null) { mpDirectionsService =MPDirectionsService(this) mpDirectionsService?.setRouteResultListener(this) } mpDirectionsService?.setTravelMode(MPTravelMode.WALKING)//Queries the MPRouting provider for a route with the hardcoded user location and the point from a location. mpDirectionsService?.query(mUserLocation, mpLocation.point)}