Discover API SDK + Search UI SDK + Maps SDK
Note
This example is a part of the Search SDK for Android sample app. You can find the values for all referenced resources in the res
directory. For example, see res/values/strings.xml
for R.string.*
references used in this example.
Besides Discover API SDK and Search UI SDK this example also uses utility class SampleAppUtils.kt and Mapbox Maps SDK. You need to add it as a dependency using the Maps SDK v10 installation instructions.
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"> <com.mapbox.maps.MapViewandroid:id="@+id/map_view"android:layout_width="0dp"android:layout_height="0dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:mapbox_logoGravity="bottom"/> <Buttonandroid:id="@+id/search_nearby"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginHorizontal="32dp"android:layout_marginBottom="16dp"android:background="@drawable/card_background"android:text="@string/discover_api_search_nearby"app:layout_constraintBottom_toTopOf="@+id/search_this_area"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"/> <Buttonandroid:id="@+id/search_this_area"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_margin="32dp"android:background="@drawable/card_background"android:text="@string/discover_api_search_in_area"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"/> <androidx.coordinatorlayout.widget.CoordinatorLayoutandroid:id="@+id/search_container_view"android:layout_width="match_parent"android:layout_height="match_parent"android:elevation="@dimen/search_card_elevation"> <com.mapbox.search.ui.view.place.SearchPlaceBottomSheetViewandroid:id="@+id/search_place_view"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:elevation="@dimen/search_card_elevation"/></androidx.coordinatorlayout.widget.CoordinatorLayout></androidx.constraintlayout.widget.ConstraintLayout>
package com.mapbox.search.sample import android.Manifestimport android.os.Bundleimport android.util.Logimport android.view.Viewimport androidx.appcompat.app.AppCompatActivityimport androidx.core.app.ActivityCompatimport androidx.lifecycle.lifecycleScopeimport com.mapbox.android.core.location.LocationEngineimport com.mapbox.android.core.location.LocationEngineProviderimport com.mapbox.geojson.Pointimport com.mapbox.maps.CameraOptionsimport com.mapbox.maps.EdgeInsetsimport com.mapbox.maps.MapViewimport com.mapbox.maps.MapboxMapimport com.mapbox.maps.Styleimport com.mapbox.maps.extension.style.layers.properties.generated.IconAnchorimport com.mapbox.maps.plugin.annotation.annotationsimport com.mapbox.maps.plugin.annotation.generated.PointAnnotationOptionsimport com.mapbox.maps.plugin.annotation.generated.createPointAnnotationManagerimport com.mapbox.maps.plugin.locationcomponent.OnIndicatorPositionChangedListenerimport com.mapbox.maps.plugin.locationcomponent.locationimport com.mapbox.search.discover.DiscoverApiimport com.mapbox.search.discover.DiscoverApiAddressimport com.mapbox.search.discover.DiscoverApiOptionsimport com.mapbox.search.discover.DiscoverApiQueryimport com.mapbox.search.discover.DiscoverApiResultimport com.mapbox.search.result.SearchAddressimport com.mapbox.search.result.SearchResultTypeimport com.mapbox.search.ui.view.CommonSearchViewConfigurationimport com.mapbox.search.ui.view.DistanceUnitTypeimport com.mapbox.search.ui.view.place.SearchPlaceimport com.mapbox.search.ui.view.place.SearchPlaceBottomSheetViewimport java.util.UUID class DiscoverApiUiActivity : AppCompatActivity() { private lateinit var discoverApi: DiscoverApiprivate lateinit var locationEngine: LocationEngine private lateinit var mapView: MapViewprivate lateinit var mapboxMap: MapboxMapprivate lateinit var mapMarkersManager: MapMarkersManager private lateinit var searchNearby: Viewprivate lateinit var searchThisArea: View private lateinit var searchPlaceView: SearchPlaceBottomSheetView override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_discover_api) discoverApi = DiscoverApi.create(getString(R.string.mapbox_access_token))locationEngine = LocationEngineProvider.getBestLocationEngine(applicationContext) mapView = findViewById(R.id.map_view)mapMarkersManager = MapMarkersManager(mapView)mapView.getMapboxMap().also { mapboxMap ->this.mapboxMap = mapboxMap mapboxMap.loadStyleUri(Style.MAPBOX_STREETS) {mapView.location.updateSettings {enabled = true} mapView.location.addOnIndicatorPositionChangedListener(object : OnIndicatorPositionChangedListener {override fun onIndicatorPositionChanged(point: Point) {mapView.getMapboxMap().setCamera(CameraOptions.Builder().center(point).zoom(14.0).build()) mapView.location.removeOnIndicatorPositionChangedListener(this)}})}} searchNearby = findViewById(R.id.search_nearby)searchNearby.setOnClickListener {locationEngine.lastKnownLocation(this) { location ->if (location == null) {return@lastKnownLocation} lifecycleScope.launchWhenStarted {val response = discoverApi.search(query = DiscoverApiQuery.Category.COFFEE_SHOP_CAFE,proximity = location,options = DiscoverApiOptions(limit = 20)) response.onValue { results ->mapMarkersManager.showResults(results)}.onError { e ->Log.d("DiscoverApiExample", "Error happened during search request", e)showToast(R.string.discover_api_search_error)}}}} searchThisArea = findViewById(R.id.search_this_area)searchThisArea.setOnClickListener {lifecycleScope.launchWhenStarted {val response = discoverApi.search(query = DiscoverApiQuery.Category.COFFEE_SHOP_CAFE,region = mapboxMap.getCameraBoundingBox(),options = DiscoverApiOptions(limit = 20)) response.onValue { results ->mapMarkersManager.showResults(results)}.onError { e ->Log.d("DiscoverApiExample", "Error happened during search request", e)showToast(R.string.discover_api_search_error)}}} searchPlaceView = findViewById<SearchPlaceBottomSheetView>(R.id.search_place_view).apply {initialize(CommonSearchViewConfiguration(DistanceUnitType.IMPERIAL))isFavoriteButtonVisible = falseaddOnCloseClickListener {mapMarkersManager.adjustMarkersForClosedCard()searchPlaceView.hide()}} mapMarkersManager.onResultClickListener = { result ->mapMarkersManager.adjustMarkersForOpenCard()searchPlaceView.open(result.toSearchPlace())locationEngine.userDistanceTo(this@DiscoverApiUiActivity, result.coordinate) { distance ->distance?.let { searchPlaceView.updateDistance(distance) }}} if (!isPermissionGranted(Manifest.permission.ACCESS_FINE_LOCATION)) {ActivityCompat.requestPermissions(this,arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION),PERMISSIONS_REQUEST_LOCATION)}} private class MapMarkersManager(mapView: MapView) { private val annotations = mutableMapOf<Long, DiscoverApiResult>()private val mapboxMap: MapboxMap = mapView.getMapboxMap()private val pointAnnotationManager = mapView.annotations.createPointAnnotationManager(null)private val pinBitmap = mapView.context.bitmapFromDrawableRes(R.drawable.red_marker) var onResultClickListener: ((DiscoverApiResult) -> Unit)? = null init {pointAnnotationManager.addClickListener {annotations[it.id]?.let { result ->onResultClickListener?.invoke(result)}true}} fun clearMarkers() {pointAnnotationManager.deleteAll()annotations.clear()} fun adjustMarkersForOpenCard() {val coordinates = annotations.values.map { it.coordinate }val cameraOptions = mapboxMap.cameraForCoordinates(coordinates, MARKERS_INSETS_OPEN_CARD, bearing = null, pitch = null)mapboxMap.setCamera(cameraOptions)} fun adjustMarkersForClosedCard() {val coordinates = annotations.values.map { it.coordinate }val cameraOptions = mapboxMap.cameraForCoordinates(coordinates, MARKERS_INSETS, bearing = null, pitch = null)mapboxMap.setCamera(cameraOptions)} fun showResults(results: List<DiscoverApiResult>) {clearMarkers()if (results.isEmpty() || pinBitmap == null) {return} val coordinates = ArrayList<Point>(results.size)results.forEach { result ->val options = PointAnnotationOptions().withPoint(result.coordinate).withIconImage(pinBitmap).withIconAnchor(IconAnchor.BOTTOM) val annotation = pointAnnotationManager.create(options)annotations[annotation.id] = resultcoordinates.add(result.coordinate)} val cameraOptions = mapboxMap.cameraForCoordinates(coordinates, MARKERS_INSETS, bearing = null, pitch = null)mapboxMap.setCamera(cameraOptions)}} private companion object { const val PERMISSIONS_REQUEST_LOCATION = 0 val MARKERS_BOTTOM_OFFSET = dpToPx(176).toDouble()val MARKERS_EDGE_OFFSET = dpToPx(64).toDouble()val PLACE_CARD_HEIGHT = dpToPx(300).toDouble() val MARKERS_INSETS = EdgeInsets(MARKERS_EDGE_OFFSET, MARKERS_EDGE_OFFSET, MARKERS_BOTTOM_OFFSET, MARKERS_EDGE_OFFSET) val MARKERS_INSETS_OPEN_CARD = EdgeInsets(MARKERS_EDGE_OFFSET, MARKERS_EDGE_OFFSET, PLACE_CARD_HEIGHT, MARKERS_EDGE_OFFSET) fun DiscoverApiAddress.toSearchAddress(): SearchAddress {return SearchAddress(houseNumber = houseNumber,street = street,neighborhood = neighborhood,locality = locality,postcode = postcode,place = place,district = district,region = region,country = country)} fun DiscoverApiResult.toSearchPlace(): SearchPlace {return SearchPlace(id = name + UUID.randomUUID().toString(),name = name,descriptionText = null,address = address.toSearchAddress(),resultTypes = listOf(SearchResultType.POI),record = null,coordinate = coordinate,routablePoints = routablePoints,categories = categories,makiIcon = makiIcon,metadata = null,distanceMeters = null,feedback = null,)}}}