When Mapbox is upgraded to V10(I went straight to the current version, V10.3), you can do what you want.

This section introduces some of the usage on V10, and finally shows how to draw a gradient motion trace to support continuous additions:

The official documentation (docs.mapbox.com/android/map…). Some of these cases are not repeated

UISettings:

PreV10 got UISettings via MapView and took control of the properties. V10 UISettings have been removed and are no longer managed in a unified way.

See controls for related attributes:

mMapView.compass.visibility = false mMapView.logo.enabled = false mMapView.attribution.enabled = false MMapView. Gestures. UpdateSettings {null} / / control can't touchCopy the code

PreV10: PreV10: Camera animation PreV10: Camera animation PreV10: Camera animation PreV10: Camera animation PreV10: Camera animation Note that Point construction longitude is the first prarams.

Ordinary camera

fun moveCamera(
        mapView: MapView,
        originalList: List<Point>,
        paddingStart: Double,
        paddingTop: Double,
        paddingEnd: Double,
        paddingBottom: Double
    ) {
        if (originalList.isEmpty()) {
            return
        }
        val mapboxMap = mapView.getMapboxMap()
        val camera = mapboxMap.cameraForCoordinates(originalList, EdgeInsets(paddingTop, paddingStart, paddingBottom, paddingEnd))
        mapView.camera.flyTo(camera)
//        mapboxMap.setCamera(camera)
    }
Copy the code

EaseTo () : animationOptions: easeTo() : animationOptions: easeTo() : animationOptions: easeTo()

fun easeCamera(mapView:MapView, originalList: List<Point>, margin: Double, duration: Long, actionAfter: (() -> Unit)? = null){ if (originalList.isEmpty()) { return } val animationOptions = MapAnimationOptions.mapAnimationOptions { duration(duration) // owner(MapAnimationOwnerRegistry.GESTURES) animatorListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { actionAfter? .invoke() } }) } val mapboxMap = mapView.getMapboxMap() val camera = mapboxMap.cameraForCoordinates(originalList, EdgeInsets(margin, margin, margin, margin)) mapView.camera.easeTo(camera, animationOptions) }Copy the code

LatlngBounds:

Class Pre10, and you can create a LatlngBounds from the List, and then getCenter(). V10 removes the LatlngBounds directly, so you don’t get the List’s corresponding getCenter(). Instead of looking carefully to see if there is an alternative to the API, we implemented the extension ourselves:

@JvmStatic
fun getCenter(originalList: List<Point>): Point? {
  if (originalList.isEmpty()) {
    return null
  }
  if (originalList.size < 2) {
    return originalList[0]
  }
  val multiPoint = MultiPoint.fromLngLats(originalList)
  val boundingBox = multiPoint.createBoundingBoxFromPoints()
  return boundingBox?.getCenter()
}
Copy the code

Add extension methods to BoundingBox and MultiPoint classes:

/ * * * * by southwest, northeast two points to construct BoundingBox object * * / fun MultiPoint. CreateBoundingBoxFromPoints () : BoundingBox? { val coordinates = coordinates() if (coordinates.size > 1){ var minLat: Double = MAX_LATITUDE var minLon: Double = MAX_LONGITUDE var maxLat: Double = MIN_LATITUDE var maxLon: Double = MIN_LONGITUDE for (gp in coordinates) { val latitude: Double = gp.latitude() val longitude: Double = gp.longitude() minLat = Math.min(minLat, latitude) minLon = Math.min(minLon, longitude) maxLat = Math.max(maxLat, latitude) maxLon = Math.max(maxLon, longitude) } val southwest = Point.fromLngLat(minLon, minLat) val northeast = Point.fromLngLat(maxLon, MaxLat) return BoundingBox. FromPoints (southwest, northeast)} return null} /** ** extend BoundingBox getCenter(). **/ fun BoundingBox.getCenter(): Point {val centerLon = (southwest().longitude() + northeast().longitude())/2.0 val centerLon = (southwest().latitude() + northeast().latitude())/2.0 return point.fromlnglat (centerLon, centerLat)}Copy the code

Set the Layer Style

V10 added a DSL build to add source and layer, relatively, source and layer are concentrated in the block builder{}, in practice, usually add source and layer are separated, dynamic, through the sourceID, AddLayerBelow (layer, layId), addLayerBelow(layer, layId) AddImages (imagesMap) is missing from the previous API, and multiple images can no longer be added at once. Instead, a simple extension function can be added.

fun Style.addImages(imageMap: Map<String, Bitmap>) {
    imageMap.forEach { (t, u) ->
        addImage(t, u)
    }
}
Copy the code

Create the case for the SymbolLayer and Source (Feature)

private fun createSymbolLayer( layerId: String, sourceId: String, isChangeStyle: Boolean, offsetY: Float ): SymbolLayer { return symbolLayer(layerId, SourceId){iconImage(PROPERTY_ICON_NAME_PATTERN) iconAllowOverlap(true) iconSize(if (isChangeStyle) 1.0 else 0.0) IconIgnorePlacement (true) iconOffset(listOf(0.0, offsety.todouble ()))}} // Control the iconSize size is convenient for animation. private fun createSymbolBitmap(latLng: Point, markerStr: String, markerParams: MarkerParams?) { val feature = Feature.fromGeometry(Point.fromLngLat(latLng.longitude(), latLng.latitude())) val bitmap = createMarkerBitmap(mContext, markerParams!!) feature.addStringProperty(PROPERTY_ICON_NAME, markerStr) imagesMap[markerStr] = bitmap markerCoordinates.add(feature) }Copy the code

Add the corresponding source and Layer

style.addSource(
                geoJsonSource(END_SOURCE_ID){
                    featureCollection(FeatureCollection.fromFeatures(markerCoordinates))
                }
            )
​
style.addLayer(endSymbolLayer)
Copy the code

Draw the track LineLayer

Also add source before adding Layer, List builds FeatureCollection as follows:

mMapView.getMapboxMap().getStyle()? .addSource( geoJsonSource(sourceId){ featureCollection( FeatureCollection.fromFeatures( arrayOf( Feature.fromGeometry( Linestring. fromLngLats(points))))) lineMetrics(true) // Note here that this line is needed to draw LineGradient. })Copy the code

Add a monochrome LineLayer

mMapView.getMapboxMap().getStyle()? AddLayer (lineLayer (layerId, sourceId) {lineDasharray (listOf (0.01, ROUND) lineCap(linecap.round) lineJoin(linejoin.round) lineWidth(trace_width.todouble ()) lineColor(pathColor)})Copy the code

Draw LineGradient, first talk about Pre10 scheme

/** * Defines a gradient with which to color a line feature. Can only be used with GeoJSON sources that specify `"lineMetrics": true`. * * @param expression an expression statement * @return property wrapper around an expression statement */ public  static PropertyValue<Expression> lineGradient(Expression expression) { return new PaintPropertyValue<>("line-gradient",  expression); } /** Produces continuous, smooth results by interpolating between pairs of input and output values ("stops"). The `input` may be any numeric expression (e.g., `["get", "population"]`). Stop inputs must be numeric literals in strictly ascending order. The output type must be `number`, `array<number>`, or `color`. Example usage: FillLayer fillLayer = new FillLayer("layer-id", "source-id"); Filllayer.setproperties (fillColor(interpolate(interpolate(exponential(0.5f), zoom(), stop(1.0f, color(color.red)), stop(5.0f, interpolate(interpolate(exponential(0.5f), zoom(), interpolate(interpolate(exponential(0.5f))), Color (color.blue)), stop(10.0f, color(color.green))))); Params: Interpolation -- Type of Accommodation number -- The input expression stops -- pair of input and output values Returns: expression See Also: Style specification */ public static Expression interpolate(@NonNull Interpolator interpolation, @NonNull Expression number, Stop... stops) { return interpolate(interpolation, number, Stop.toExpressionArray(stops)); }Copy the code

Simply create expression. Stop[] Stops and draw LineGradient according to the speed of each Point in the List.

In V10 there is no longer a Stop class under Expression, so there is no way to create Stop[]. In the official demo, Stop {} is a variable parameter, so we want to build a Stop {}.

private fun createHeatmapLayer(): HeatmapLayer { return heatmapLayer( HEATMAP_LAYER_ID, EARTHQUAKE_SOURCE_ID) {maxZoom(9.0) sourceLayer(HEATMAP_LAYER_SOURCE) // Begin color ramp at 0-stop with a 0-transparancy color // to create a blur-like effect. heatmapColor( interpolate { linear() heatmapDensity() stop { Literal (0) rgba(33.0, 102.0, 172.0, 0.0)} stop {literal(0.2) RGB (103.0, 169.0, 0) Literal (0)} stop {literal(0.4) RGB (209.0, 229.0, 240.0)} stop {literal(0.6) RGB (253.0, 219.0, 0) Literal (0.8) RGB (239.0, 138.0, 98.0)} stop {literal(1) RGB (178.0, 24.0, 43.0)}})... . }}Copy the code

In fact, stop{} source code is as follows, so you need to provide an array of higher-order functions

fun stop(block: ExpressionBuilder. () - > Unit) {[email protected] (block)} / / give Expression. Add a InterpolatorBuilder The expansion of the stops () method can be fun Expression. InterpolatorBuilder. Stops (stopList: Array < (Expression. ExpressionBuilder. () - > Unit)? >){ stopList.forEach { stop -> stop? .let {apply(it)}}} // Pass the above extension method as a parameter to build Expression as the last parameter, Interpolate {linear() lineProgress() stops(colorStops)} var colorExpression = expression.interpolate {linear() lineProgress() stops(colorStops) The lineGradient(colorExpression) can be used as a parameter to construct lineLayer. Mmapview.getmapboxmap ().getStyle()?.addLayer(lineLayer(layerId, SourceId){lineCap(linecap.round) lineJoin(linejoin.round) lineWidth(5.0) lineGradient(colorExpression)})Copy the code

At the end of this post, I will post a photo of my previous ice-skating route to Orson: