|
In this guide you will learn how to compute and render a route on an interactive map, from a departure position to a desired destination.
The app also includes a search button which searches along the selected route for points of interest (POIs) such as fuel stations, and displays the results of the search in a scrollable pop-up panel.
Search results along the computed route
Routing
A RoutingService()
is instantiated to compute and render the route.
The onStarted
and onCompleted
routing callbacks are overridden and implemented, to show, and then hide, respectively, the routing computation progress bar, which is useful for very slow devices, where the route computation may take long enough to be noticeable by the user.
When the route calculation is completed, if there is no error, the resulting routes (as there could be more than one alternate route in the resulting set between the specified departure and destination points) are drawn on the map:
gemSurfaceView.mapView?.presentRoutes()
and a main route is choosen mainRoute = routes[0]
.
Then the search button is set to visible searchButton.visibility = View.VISIBLE
, so that the user can search the landmarks present along the route.
private val routingService = RoutingService(
onStarted = {
progressBar.visibility = View.VISIBLE
},
onCompleted = { routes, errorCode, _ ->
progressBar.visibility = View.GONE
when (errorCode)
{
GemError.NoError ->
{
if(routes.isNotEmpty())
{
routesList = routes
mainRoute = routes[0]
Util.postOnMain {
searchButton.visibility = View.VISIBLE
}
SdkCall.execute {
gemSurfaceView.mapView?.presentRoutes(routes, displayBubble = true)
}
}
}
GemError.Cancel ->
{
}
else ->
{
showDialog("Routing service error: ${GemError.getMessage(errorCode)}")
}
}
}
)
The function calculateRoute()
is used to set the waypoints and to initiate the route calculation.
The starting, or departure point of the route is the first waypoint in a list of 2 or more Landmarks (2 in this case), each containing a name, latitude (in degrees) and longitude (in degrees). The destination point is the last waypoint in the list.
private fun calculateRoute() = SdkCall.execute {
val waypoints = arrayListOf(
Landmark("Folkestone", 51.0814, 1.1695),
Landmark("Paris", 48.8566932, 2.3514616)
)
routingService.calculateRoute(waypoints)
}
Search
A SearchService()
is instantiated, which carries out on-demand search along the route.
private val searchService = SearchService(
onStarted = {
progressBar.visibility = View.VISIBLE
},
onCompleted = onCompleted@{ results, errorCode, _ ->
progressBar.visibility = View.GONE
when (errorCode) {
GemError.NoError -> {
onSearchCompleted(results)
}
GemError.Cancel -> {
}
else -> {
Toast.makeText(
this@MainActivity,
"Search service error: ${GemError.getMessage(errorCode)}",
Toast.LENGTH_SHORT
).show()
}
}
}
)
When the user clicks the search button, the searchAlongRoute()
function is called and set to return up to 25 gas stations (defined as EGenericCategoriesIDs.GasStation
) along the route.
private fun searchAlongRoute(route: Route) = SdkCall.execute {
searchService.preferences.maxMatches = 25
searchService.searchAlongRoute(route, EGenericCategoriesIDs.GasStation)
}
The onCompleted
listener in the searchService
calls the onSearchCompleted()
function when the user-triggered search is finished.
Then the results are displayed in a scrollable list inside a pop-up panel.
private fun onSearchCompleted(results: ArrayList<Landmark>) {
val builder = AlertDialog.Builder(this)
val convertView = layoutInflater.inflate(R.layout.dialog_list, null)
convertView.findViewById<RecyclerView>(R.id.list_view).apply {
layoutManager = LinearLayoutManager(this@MainActivity)
addItemDecoration(DividerItemDecoration(
applicationContext,
(layoutManager as LinearLayoutManager).orientation
))
setBackgroundResource(R.color.background_color)
val lateralPadding = resources.getDimension(R.dimen.big_padding).toInt()
setPadding(lateralPadding, 0, lateralPadding, 0)
adapter = CustomAdapter(results)
}
builder.setView(convertView)
builder.create().show()
}
Map Implementation
When the map data is ready using the onMapDataReady@{}
callback it calculates the route using the function calculateRoute()
and then attaches a touch event to the Map View
as seen in gemSurfaceView.mapView?.onTouch = {}
.
This touch event which will set, gemSurfaceView.mapView?.apply {...}
, the main route to be highlighted and centered on.
Searching along the route is triggered at the user’s discretion using the searchButton
.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
progressBar = findViewById(R.id.progressBar)
gemSurfaceView = findViewById(R.id.gem_surface)
searchButton = findViewById(R.id.search_button)
SdkSettings.onMapDataReady = onMapDataReady@{ isReady ->
if (!isReady) return@onMapDataReady
calculateRoute()
gemSurfaceView.mapView?.onTouch = { xy ->
SdkCall.execute {
gemSurfaceView.mapView?.cursorScreenPosition = xy
val routes = gemSurfaceView.mapView?.cursorSelectionRoutes
if (!routes.isNullOrEmpty())
{
mainRoute = routes[0]
gemSurfaceView.mapView?.apply {
preferences?.routes?.mainRoute = mainRoute
centerOnRoutes(routesList)
}
}
}
}
searchButton.setOnClickListener {
searchAlongRoute(mainRoute)
}
}
}