如何使用 Mapbox Android SKD 从本地 geojson 属性设置图标类型

How do I set icon type from local geojson properties using Mapbox Android SKD

我有一个带有图标标记的漂亮地图和一个使用 Mapbox 的 recyclerview 设置。类似这样:

https://docs.mapbox.com/android/maps/examples/recyclerview-interaction

我的问题是我不知道如何根据我的本地设置图标 json 属性。我总共需要使用大约 40 个不同的图标,所以我认为最好的设置位置是在我的 geojson 属性中。我的 drawable-xxhdpi 文件夹中有图标的 png 文件。这是我的本地 geojson 文件的样子:

{
  "type": "Feature",
  "properties": {
    "name": "Broadway",
    "icon": "route_icon_1",
    "hours": "V1",
    "phone": "One Star Rating",
    "description": "Located at Lower Point Boulders"
  },
  "geometry": {
    "type": "Point",
    "coordinates": [
      -86.311166,
      33.919872
    ]
  }
},
{
  "type": "Feature",
  "properties": {
    "name": "Return of the Jedi",
    "icon": "route_icon_2",
    "hours": "V7",
    "phone": "One Star Rating",
    "description": "Located at Lower Point Boulders"
  },
  "geometry": {
    "type": "Point",
    "coordinates": [
      -86.311174,
      33.919883
    ]
  }
},

我正在访问 geojson 文件,一切正常 运行,但我似乎无法根据 属性 中的“图标”设置我的图标geojson 文件。这可能吗?我为我的代码的长度道歉。这是我第一次在这里提问,我不确定我应该写多少代码 post。

这是我地图中的代码 activity:

class MapActivity : AppCompatActivity(), OnMapReadyCallback, LocationRecyclerViewAdapter.ClickListener,
MapboxMap.OnMapClickListener {
private var featureCollection: FeatureCollection? = null
private var mapboxMap: MapboxMap? = null
private var mapView: MapView? = null
private var locationsRecyclerView: RecyclerView? = null
private var listOfIndividualLocations: ArrayList<IndividualLocation>? = null
private var styleRvAdapter: LocationRecyclerViewAdapter? = null

private var markerSelected = false
private var markerAnimator: ValueAnimator? = null

private var selectedMarkerIcon: Bitmap? = null
private var unselectedMarkerIcon: Bitmap? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Configure the Mapbox access token. Configuration can either be called in your application
    // class or in the same activity which contains the mapview.
    Mapbox.getInstance(this, getString(R.string.access_token))

    // Hide the status bar for the map to fill the entire screen
    @Suppress("DEPRECATION")
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        window.insetsController?.hide(WindowInsets.Type.statusBars())
    } else {
        window.setFlags(
            WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN
        )
    }

    // Inflate the layout with the the MapView. Always inflate this after the Mapbox access token is configured.
    setContentView(R.layout.activity_map)

    // Create a GeoJSON feature collection from the GeoJSON file in the assets folder.
    try {
        featureCollectionFromJson
    } catch (exception: Exception) {
        Log.e("MapActivity", "onCreate: $exception")
        Toast.makeText(this, R.string.failure_to_load_file, Toast.LENGTH_LONG).show()
    }

    // Initialize a list of IndividualLocation objects for future use with recyclerview
    listOfIndividualLocations = ArrayList()

    // Set up the Mapbox map
    mapView = findViewById(R.id.mapView)
    mapView?.onCreate(savedInstanceState)
    mapView?.getMapAsync(this)
}

 override fun onMapReady(mapboxMap: MapboxMap) {
     this.mapboxMap = mapboxMap
     // Initialize the custom class that handles marker icon creation and map styling based on the selected theme



     selectedMarkerIcon = BitmapFactory.decodeResource(
         resources,
         R.drawable.basic_red_marker
     )


     unselectedMarkerIcon = BitmapFactory.decodeResource(
         resources,
         R.drawable.basic_red_marker
     )


     mapboxMap.setStyle(
         Style.MAPBOX_STREETS
     )

     { style ->
         // Setting the returned mapboxMap object (directly above) equal to the "globally declared" one
         this@MapActivity.mapboxMap = mapboxMap

         mapboxMap.addOnMapClickListener(this)

         val quad = LatLngQuad(
             LatLng(33.92307338188975, -86.31129446659145),
             LatLng(33.92307338188975, -86.30688718139171),
             LatLng(33.91948714730282, -86.30688718139171),
             LatLng(33.91948714730282, -86.31129446659145)
         )

         val quad2 = LatLngQuad(
             LatLng(33.921356, -86.307309),
             LatLng(33.921356, -86.307156),
             LatLng(33.921200, -86.307156),
             LatLng(33.921200, -86.307309)
         )

         // Add an ImageSource to the map
         style.addSource(ImageSource(ID_IMAGE_SOURCE, quad, R.drawable.asset14))
         style.addSource(ImageSource(ID_IMAGE_SOURCE_VANDALA, quad2, R.drawable.vandala_overlay_sm))
         // Create a raster layer and use the imageSource's ID as the layer's data. Then add a RasterLayer to the map.
         style.addLayerBelow(
             RasterLayer(ID_IMAGE_LAYER, ID_IMAGE_SOURCE),
             LAYER_ID
         )
         style.addLayerAbove(
             RasterLayer(ID_IMAGE_LAYER_VANDALA, ID_IMAGE_SOURCE_VANDALA),
             ID_IMAGE_LAYER
         )

         // Set bounds for the map camera so that the user can't pan the map outside of the NYC area
         mapboxMap.setLatLngBoundsForCameraTarget(LOCKED_MAP_CAMERA_BOUNDS)

         // Set up the SymbolLayer which will show the icons for each route location
         initRouteLocationIconSymbolLayer()

         // Set up the SymbolLayer which will show the selected route icon
         initSelectedRouteSymbolLayer()

         // Create a list of features from the feature collection
         if (featureCollection != null) {
             val featureList: List<Feature> = featureCollection?.features() as List<Feature>

             // Retrieve and update the source designated for showing the route location icons
             mapboxMap.style?.getSourceAs<GeoJsonSource?>(SOURCE_ID)!!
                 .setGeoJson(FeatureCollection.fromFeatures(featureList))
             for (x in featureList.indices) {
                 val singleLocation: Feature = featureList[x]

                 // Get the single location's String properties to place in its map marker
                 val singleLocationName: String =
                     singleLocation.getStringProperty("name")
                 val singleLocationRouteIcon: String =
                     singleLocation.getStringProperty("icon")
                 Log.e("tag", singleLocationRouteIcon)
                 val singleLocationHours: String =
                     singleLocation.getStringProperty("hours")
                 val singleLocationDescription: String =
                     singleLocation.getStringProperty("description")
                 val singleLocationPhoneNum: String =
                     singleLocation.getStringProperty("phone")


                 // Add a boolean property to use for adjusting the icon of the selected route location
                 singleLocation.addBooleanProperty(PROPERTY_SELECTED, false)

                 // Get the single location's LatLng coordinates
                 val singleLocationPosition: Point = singleLocation.geometry() as Point

                 // Create a new LatLng object with the Position object created above
                 val singleLocationLatLng = LatLng(
                     singleLocationPosition.latitude(),
                     singleLocationPosition.longitude()
                 )

                 // Add the location to the Arraylist of locations for later use in the recyclerview
                 listOfIndividualLocations!!.add(
                     IndividualLocation(
                         singleLocationName,
                         singleLocationRouteIcon,
                         singleLocationDescription,
                         singleLocationHours,
                         singleLocationPhoneNum,
                         singleLocationLatLng
                     )
                 )
             }
         }

         // the Maps SDK's LocationComponent can be used to easily display and customize
         // the device location's puck
         setUpRecyclerViewOfLocationCards()
         Toast.makeText(this@MapActivity, "Click on a card", Toast.LENGTH_SHORT)
             .show()
     }
 }


 override fun onMapClick(point: LatLng): Boolean {
    Log.e("tag", "onMapClick")
    val style = mapboxMap!!.style
    if (style != null) {
        val selectedMarkerSymbolLayer = style.getLayer("selected-route-location-layer-id") as SymbolLayer?
        val pixel = mapboxMap!!.projection.toScreenLocation(point)
        val features = mapboxMap!!.queryRenderedFeatures(pixel, "route-location-layer-id")
        val selectedFeature = mapboxMap!!.queryRenderedFeatures(
            pixel, "selected-route-location-layer-id"
        )
        if (selectedFeature.size > 0 && markerSelected) {
            Log.e(
                "tag",
                "1 onMapClick: selectedFeature.size > 0 && markerSelected ${selectedFeature.size} $markerSelected"
            )
            return false
        }
        if (features.isEmpty()) {
            Log.e("tag", "2 onMapClick: features.isEmpty")
            if (markerSelected) {
                Log.e("tag", "selectMarker = true")
                deselectMarker(selectedMarkerSymbolLayer!!)
            }
            return false
        }
        val source = style.getSourceAs<GeoJsonSource>(ID_SELECTED_ROUTE_ICON)
        source?.setGeoJson(
            FeatureCollection.fromFeatures(
                arrayOf(
                    Feature.fromGeometry(
                        features[0].geometry()
                    )
                )
            )
        )
        if (markerSelected) {
            Log.e("tag", "3 onMapClick: selectMarker")
            deselectMarker(selectedMarkerSymbolLayer!!)
        }
        if (features.size > 0) {
            Log.e("tag", "4 onMapClick: features.size > 0")
            Log.e("tag", "4 onMapClick: features.size = ${features.size}")
            selectMarker(selectedMarkerSymbolLayer!!)
        }
    }
    handleClickIcon(mapboxMap?.projection!!.toScreenLocation(point))
    return true
}


 private fun handleClickIcon(screenPoint: PointF): Boolean {
    Log.e("tag", "handleClickIcon")
    val features: List<Feature> = mapboxMap?.queryRenderedFeatures(
        screenPoint,
        LAYER_ID,
        "route-location-layer-id"
    ) as List<Feature>

    return if (features.isNotEmpty()) {
        Log.e("tag", "1 handleClickIcon: features.isNotEmpty")
        val name: String = features[0].getStringProperty("name")
        val featureList: List<Feature> = featureCollection?.features() as List<Feature>
        for (i in featureList.indices) {
            if (featureList[i].getStringProperty("name") == name) {
                Log.e("tag", "(${featureList[i].getStringProperty("name")} == $name)")
                val selectedFeaturePoint: Point = featureList[i].geometry() as Point
                Log.e("tag", "handleClickIcon: featureSelectStatus = ${featureSelectStatus(i)}")

                if (featureSelectStatus(i)) {
                    Log.e("tag", "${featureSelectStatus(i)}")
                    Log.e(
                        "tag", "2 handleClickIcon: featureSelectStatus = ${
                            featureSelectStatus(
                                i
                            )
                        }"
                    )
                    setFeatureSelectState(featureList[i], true)
                    Log.e(
                        "tag",
                        "2 handleClickIcon: setFeatureSelectState(featureList $i: selectedState set to false)"
                    )

                } else {
                    Log.e(
                        "tag", "3 handleClickIcon: featureSelectStatus = ${
                            featureSelectStatus(
                                i
                            )
                        }"
                    )
                    setSelected(i)
                }
                if (selectedFeaturePoint.latitude() != MOCK_DEVICE_LOCATION_LAT_LNG.latitude) {
                    Log.e(
                        "tag",
                        "selectedFeaturePoint.latitude != MOCK_DEVICE_LOCATION_LAT_LNG.latitude"
                    )
                    for (x in 0 until featureCollection!!.features()!!.size) {
                        if (listOfIndividualLocations!![x].getLocation()?.latitude == selectedFeaturePoint.latitude()) {
                            // Scroll the recyclerview to the selected marker's card. It's "x-1" below because
                            // the mock device location marker is part of the marker list but doesn't have its own card
                            // in the actual recyclerview.
                            locationsRecyclerView!!.smoothScrollToPosition(x)
                            Log.e("tag", "smoothScrollToPosition")
                        }
                    }
                }
            }
            else
            {
                setFeatureSelectState(featureList[i], false)
                Log.e("tag", "4 handleClickIcon: (${featureList[i]}")
            }
        }
        true
    }
    else
    {
        false
    }
}

 private fun selectMarker(iconLayer: SymbolLayer) {
    Log.e("tag", "selectMarker: markerSelect set to true")
    markerAnimator = ValueAnimator()
    markerAnimator!!.setObjectValues(1f, 2f)
    markerAnimator!!.duration = 300
    markerAnimator!!.addUpdateListener { animator ->
        iconLayer.setProperties(
            iconSize(animator.animatedValue as Float)
        )
    }
    markerAnimator!!.start()
    markerSelected = true
}


 private fun deselectMarker(iconLayer: SymbolLayer) {
    Log.e("tag", "deselectMarker: markerSelect set to false")
    markerAnimator!!.setObjectValues(1.5f, 1f)
    markerAnimator!!.duration = 300
    markerAnimator!!.addUpdateListener { animator ->
        iconLayer.setProperties(
            iconSize(animator.animatedValue as Float)
        )
    }
    markerAnimator!!.start()
    markerSelected = false
}

/**
 * The LocationRecyclerViewAdapter's interface which listens to clicks on each location's card
 *
 * @param position the clicked card's position/index in the overall list of cards
 */
override fun onItemClick(position: Int) {
    Log.e("tag", "itemClick")

    // Get the selected individual location via its card's position in the recyclerview of cards
    val selectedLocation: IndividualLocation = listOfIndividualLocations!![position]

    // Evaluate each Feature's "select state" to appropriately style the location's icon
    val featureList: List<Feature> = featureCollection?.features() as List<Feature>
    val selectedLocationPoint: Point =
        featureCollection!!.features()?.get(position)?.geometry() as Point
    for (i in featureList.indices) {
        if (featureList[i].getStringProperty("name") == selectedLocation.name) {
            Log.e(
                "tag",
                "(${featureList[i].getStringProperty("name")} == ${selectedLocation.name})"
            )

            if (featureSelectStatus(i)) {
                Log.e("tag", "1 featureSelectStatus = ${featureSelectStatus(i)}")
                // setFeatureSelectState(featureList[i], false)
                Toast.makeText(
                    applicationContext,
                    "Go to ${selectedLocation.name} Details Activity",
                    Toast.LENGTH_LONG
                ).show()
                Log.e("tag", "Go to ${selectedLocation.name} Details Activity")
            } else {
                Log.e("tag", "2 itemClick: setSelected $i")
                setSelected(i)
            }
        } else {
            setFeatureSelectState(featureList[i], false)
            Log.e("tag", "3 itemClick: featureList $i: selectedState false")
        }
    }

    selectedLocation.getLocation()?.let { onCardClick(it) }
    // Reposition the map camera target to the selected marker
    repositionMapCamera(selectedLocationPoint)
}

    private fun onCardClick(point: LatLng): Boolean {
    Log.e("tag", "onCardClick")
    val style = mapboxMap!!.style
    if (style != null) {
        val selectedMarkerSymbolLayer = style.getLayer("selected-route-location-layer-id") as SymbolLayer?
        val pixel = mapboxMap!!.projection.toScreenLocation(point)
        val features = mapboxMap!!.queryRenderedFeatures(pixel, "route-location-layer-id")
        val selectedFeature = mapboxMap!!.queryRenderedFeatures(
            pixel, "selected-route-location-layer-id"
        )
        if (selectedFeature.size > 0 && markerSelected) {
            Log.e(
                "tag",
                "1 onCardClick: selectedFeature.size > 0 && markerSelected ${selectedFeature.size} $markerSelected"
            )
            return false
        }
        if (features.isEmpty()) {
            Log.e("tag", "2 onCardClick: features.isEmpty")
            if (markerSelected) {
                Log.e("tag", "Do Nothing")
            return false
            }
            else {
                Log.e("tag", "markerSelected = $markerSelected")
                selectMarker(selectedMarkerSymbolLayer!!)
            }
            return false
        }
        val source = style.getSourceAs<GeoJsonSource>(ID_SELECTED_ROUTE_ICON)
        source?.setGeoJson(
            FeatureCollection.fromFeatures(
                arrayOf(
                    Feature.fromGeometry(
                        features[0].geometry()
                    )
                )
            )
        )
        if (markerSelected) {
            Log.e("tag", "3 onCardClick: markerSelected")
            deselectMarker(selectedMarkerSymbolLayer!!)
        }
        if (features.size > 0) {
            Log.e("tag", "4 onCardClick: features.size > 0")
            Log.e("tag", "4 onCardClick: features.size = ${features.size}")
            selectMarker(selectedMarkerSymbolLayer!!)
        }
    }
    return true
}

/**
 * Adds a SymbolLayer which will show all of the location's icons
 */
private fun initRouteLocationIconSymbolLayer() {
    val style: Style? = mapboxMap?.style
    if (style != null) {
        // Add the icon image to the map
        style.addImage(
            ID_ROUTE_ICON, unselectedMarkerIcon as Bitmap
        )

        style.transition = TransitionOptions(0, 0, false)

        // Create and add the GeoJsonSource to the map
        val routeLocationGeoJsonSource = GeoJsonSource(SOURCE_ID)
        style.addSource(routeLocationGeoJsonSource)

        // Create and add the route location icon SymbolLayer to the map
        val routeLocationSymbolLayer = SymbolLayer(
            "route-location-layer-id",
            SOURCE_ID
        )
        routeLocationSymbolLayer.withProperties(
            iconImage(ID_ROUTE_ICON),
            iconAllowOverlap(true),
            iconOffset(arrayOf(0f, -9f))
        )
        style.addLayer(routeLocationSymbolLayer)
    } else {
        Log.d("RouteFinderActivity", "initRouteLocationIconSymbolLayer: Style isn't ready yet.")
        throw IllegalStateException("Style isn't ready yet.")
    }
}

/**
 * Adds a SymbolLayer which will show the selected location's icon
 */
private fun initSelectedRouteSymbolLayer() {
    val style: Style? = mapboxMap?.style
    if (style != null) {

        // Add the icon image to the map
        style.addImage(
            ID_SELECTED_ROUTE_ICON, selectedMarkerIcon as Bitmap
        )

        // Create and add the route location icon SymbolLayer to the map
        val selectedRouteLocationSymbolLayer = SymbolLayer(
            "selected-route-location-layer-id",
            SOURCE_ID
        )
        selectedRouteLocationSymbolLayer.withProperties(
            iconImage(ID_SELECTED_ROUTE_ICON),
            iconOffset(arrayOf(0f, -9f)),
            iconAllowOverlap(true)
        )
        selectedRouteLocationSymbolLayer.withFilter(eq(get(PROPERTY_SELECTED), literal(true)))
        style.addLayer(selectedRouteLocationSymbolLayer)
    } else {
        Log.d("RouteFinderActivity", "initSelectedRouteSymbolLayer: Style isn't ready yet.")
        throw IllegalStateException("Style isn't ready yet.")
    }
}

/**
 * Checks whether a Feature's boolean "selected" property is true or false
 *
 * @param index the specific Feature's index position in the FeatureCollection's list of Features.
 * @return true if "selected" is true. False if the boolean property is false.
 */
private fun featureSelectStatus(index: Int): Boolean {
    return if (featureCollection == null) {
        false
    } else featureCollection!!.features()?.get(index)?.getBooleanProperty(PROPERTY_SELECTED)!!
}

/**
 * Set a feature selected state.
 *
 * @param index the index of selected feature
                 */
private fun setSelected(index: Int) {
    Log.e("tag", "setSelected")
    val feature: Feature = featureCollection?.features()!![index]
    setFeatureSelectState(feature, true)
    Log.e(
        "tag",
        "setSelected: setFeatureSelectedState(feature = ${featureCollection?.features()!![index]}, selectedState set to true"
    )

    refreshSource()
}

/**
 * Selects the state of a feature
 *
 * @param feature the feature to be selected.
 */
private fun setFeatureSelectState(feature: Feature, selectedState: Boolean) {
    feature.properties()?.addProperty(PROPERTY_SELECTED, selectedState)
    refreshSource()
}

/**
 * Updates the display of data on the map after the FeatureCollection has been modified
 */
private fun refreshSource() {
    val source: GeoJsonSource? = mapboxMap?.style?.getSourceAs(SOURCE_ID)
    if (source != null && featureCollection != null) {
        source.setGeoJson(featureCollection)
    }
}

private fun repositionMapCamera(newTarget: Point) {
    val newCameraPosition: CameraPosition = CameraPosition.Builder()
        .target(LatLng(newTarget.latitude(), newTarget.longitude()))
        .zoom(22.0)
        .build()
    mapboxMap?.animateCamera(
        CameraUpdateFactory.newCameraPosition(newCameraPosition),
        CAMERA_MOVEMENT_SPEED_IN_MILSECS
    )
}

// Use fromJson() method to convert the GeoJSON file into a usable FeatureCollection object
@get:Throws(IOException::class)
private val featureCollectionFromJson: Unit
    get() {
        try {
            // Use fromJson() method to convert the GeoJSON file into a usable FeatureCollection object
            featureCollection = "list_of_locations.geojson".loadGeoJsonFromAsset()?.let {
                FeatureCollection.fromJson(
                    it
                )
            }
        } catch (exception: Exception) {
            Log.e("MapActivity", "getFeatureCollectionFromJson: $exception")
        }
    }

private fun String.loadGeoJsonFromAsset(): String? {
    Log.e("tag", "loadGeoJsonFromAsset")
    return try {
        // Load the GeoJSON file from the local asset folder
        val `is`: InputStream = assets.open(this)
        val size: Int = `is`.available()
        val buffer = ByteArray(size)
        `is`.read(buffer)
        `is`.close()
        String(buffer, charset("UTF-8"))
    } catch (exception: Exception) {
        Log.e("MapActivity", "Exception Loading GeoJSON: $exception")
        exception.printStackTrace()
        null
    }
}

private fun setUpRecyclerViewOfLocationCards() {
    Log.e("tag", "seUpRecyclerViewOfLocationCards")
    // Initialize the recyclerview of location cards and a custom class for automatic card scrolling
    locationsRecyclerView = findViewById(R.id.map_layout_rv)
    locationsRecyclerView?.setHasFixedSize(true)
    locationsRecyclerView?.layoutManager = LinearLayoutManagerWithSmoothScroller(this)
    styleRvAdapter = listOfIndividualLocations?.let {
        LocationRecyclerViewAdapter(
            it,
            applicationContext, this
        )
    }
    locationsRecyclerView?.adapter = styleRvAdapter
    val snapHelper: SnapHelper = LinearSnapHelper()
    snapHelper.attachToRecyclerView(locationsRecyclerView)
}

// Add the mapView's lifecycle to the activity's lifecycle methods
public override fun onResume() {
    super.onResume()
    mapView?.onResume()
}

override fun onStart() {
    super.onStart()
    mapView?.onStart()
}

override fun onStop() {
    super.onStop()
    mapView?.onStop()
}

public override fun onPause() {
    super.onPause()
    mapView?.onPause()
}

override fun onLowMemory() {
    super.onLowMemory()
    mapView?.onLowMemory()
}

override fun onDestroy() {
    super.onDestroy()
    mapView?.onDestroy()
}

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    mapView?.onSaveInstanceState(outState)
}

companion object {

    private val LOCKED_MAP_CAMERA_BOUNDS = LatLngBounds.Builder()
        .include(LatLng(33.92307338188975, -86.30688718139171))
        .include(
            LatLng(
                33.91948714730282,
                -86.31129446659145
            )
        ).build()

    private val MOCK_DEVICE_LOCATION_LAT_LNG: LatLng =
        LatLng(33.921466408978034, -86.30824978533974)
    private const val CAMERA_MOVEMENT_SPEED_IN_MILSECS = 1200
    private const val PROPERTY_SELECTED = "selected"
    private const val ID_ROUTE_ICON = "route-icon-id"
    private const val ID_SELECTED_ROUTE_ICON = "selected-route-icon-id"
    private const val LAYER_ID = "LAYER_ID"
    private const val ID_IMAGE_SOURCE = "image_source-id"
    private const val ID_IMAGE_LAYER = "image_layer-id"
    private const val ID_IMAGE_SOURCE_VANDALA = "image_source-id_vandala"
    private const val ID_IMAGE_LAYER_VANDALA = "image_layer-id_vandala"
    private const val SOURCE_ID = "route-location-source-id"
}

}

提前致谢。

你快到了。您还需要一些代码。

在您的函数 initRouteLocationIconSymbolLayer() 上,您有以下代码:

routeLocationSymbolLayer.withProperties(
            iconImage(ID_ROUTE_ICON), // <---- Here is where you have to change
            iconAllowOverlap(true),
            iconOffset(arrayOf(0f, -9f))
        )

您只设置了图层有一个图标。 MapBoxSDK 允许您使用 geojson 文件的属性。

因此,这里我们需要更改为每种类型的图标生成图标图像的方式

routeLocationSymbolLayer
     .withProperties(
         /* iconImage constructor, with some query-like code */
         iconImage(
              match(
                 get("icon"), // JSON Key to evaluate
                 literal("route_icon_1"), // default
                 stop("route_icon_1", "route_icon_1"), // stop(input,output)
                 stop("route_icon_2", "route_icon_2")
              )
         ),
        /*the remaining properties you declared*/
        iconAllowOverlap(true),
        iconOffset(arrayOf(0f, -9f)
)

来源:MapBox Android SDK Example