中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android基于Mapbox?V10如何繪制LineGradient軌跡

發布時間:2022-08-25 10:20:28 來源:億速云 閱讀:171 作者:iii 欄目:開發技術

本篇內容介紹了“Android基于Mapbox V10如何繪制LineGradient軌跡”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

前言

當Mapbox升級到V10(我直接到當前的最新V10.3)版本后,就可以就此實現自己想要實現的功能。

官方文檔上的一些case就不在重復了

UISettings:

PreV10 通過MapView 拿到UISettings, 然后控制相關屬性,V10 UISettings已經被移除了,不再統一管理,比較分散。

參見相關屬性的控制:

mMapView.compass.visibility = false
mMapView.logo.enabled = false
mMapView.attribution.enabled = false
mMapView.gestures.updateSettings { null }//控制無法觸摸

PreV10 與 V10 的Camera 相關的animation (涉及到用到的Point,PreV10 之前有LatLn, Point 兩個類,當時還覺得為啥弄兩個,比較冗余,V10里面拿掉了LatLn保留Point,注意的是Point構造時 longitude為第一個prarams. )

普通的 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)
    }

camera動畫之后,animationEnd 后的回調 需求時,傳入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)
    }

LatlngBounds:

Pre10 之前的類,并且可以通過 List 創建一個 LatlngBounds, 然后 getCenter(), V10中直接拿掉了 LatLngBounds, 也就沒有獲取List 對應的 getCenter()了,沒有仔細地去找API是否有相對應的替代,直接自己用擴展實現了一下:

@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()
}

涉及到兩個類 BoundingBox 及 MultiPoint, 在兩個類上添加擴展方法:

/**
** 通過 southwest、northeast 兩個點構建 BoundingBox 對象
**/
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
}

/**
** 擴展BoundingBox getCenter()方法。
**/
fun BoundingBox.getCenter(): Point {
    val centerLon = (southwest().longitude() + northeast().longitude())/2.0
    val centerLat = (southwest().latitude() + northeast().latitude())/2.0
    return Point.fromLngLat(centerLon, centerLat)
}

Style設定Layer

V10 添加了DSL build 添加 source、layer,相對而言source、layer都比較集中在builder{}的 block里,實際應用中通常source、layer 的添加都是分離的,動態的,通過sourceID, layerId 找到對應的 source、layer然后修改里面的內容, 發現 addLayerBelow(layer, layId) 該方法不好使,Crash了,暫且不用它了。 SymbolLayer 相比之前的api接口,少了一個 style.addImages(imagesMap), 不再支持一次性添加多個Image,添加一個簡單的擴展函數即可。

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

創建SymbolLayer 及 Source (Feature)的case

 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()))
        }
    }
// 控制iconSize 大小是方便做動畫。

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)
    }

添加對應的 source, Layer

style.addSource(
                geoJsonSource(END_SOURCE_ID){
                    featureCollection(FeatureCollection.fromFeatures(markerCoordinates))
                }
            )

style.addLayer(endSymbolLayer)

繪制軌跡LineLayer

同樣添加Layer前需要添加 source, List 構建 FeatureCollection, 如下:

mMapView.getMapboxMap().getStyle()?.addSource(
    geoJsonSource(sourceId){
        featureCollection(
            FeatureCollection.fromFeatures(
                arrayOf(
                    Feature.fromGeometry(
                        LineString.fromLngLats(points)
                    )
                )
            )
        )
        lineMetrics(true) // 注意這里,繪制LineGradient 需要添加這行代碼。
    }
)

添加單色的 LineLayer

mMapView.getMapboxMap().getStyle()?.addLayer(
                lineLayer(layerId, sourceId){
                    lineDasharray(listOf(0.01, 2.0))
                    lineCap(LineCap.ROUND)
                    lineJoin(LineJoin.ROUND)
                    lineWidth(TRACE_WIDTH.toDouble())
                    lineColor(pathColor)
                }
            )

繪制LineGradient, 先聊 Pre10的方案

 /**
   * 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(
         exponential(0.5f), zoom(),
         stop(1.0f, color(Color.RED)),
         stop(5.0f, color(Color.BLUE)),
         stop(10.0f, color(Color.GREEN))
       )
     )
 );
 
     
Params:
interpolation – type of interpolation
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));
  }

以上只需創建 Expression.Stop[] stops, 根據List 中每個Point 的配速對應的色值,傳入即可,繪制LineGradient。

V10 中不再有 Expression 下 的Stop類,所以無從談起創建Stop[] 了,從官方的demo里看 , 最后跟了不定的 stop{}, 可以看見是一個可變參數,所以打算構建一個 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, 207.0)
          }
          stop {
            literal(0.4)
            rgb(209.0, 229.0, 240.0)
          }
          stop {
            literal(0.6)
            rgb(253.0, 219.0, 240.0)
          }
          stop {
            literal(0.8)
            rgb(239.0, 138.0, 98.0)
          }
          stop {
            literal(1)
            rgb(178.0, 24.0, 43.0)
          }
        }
      )
      ...
      ...
    }
 }

其實 stop{} 的源碼如下, 所以需要提供一個高階函數的數組

    fun stop(block: ExpressionBuilder.() -> Unit) {
      this@ExpressionBuilder.apply(block)
    }

//給Expression.InterpolatorBuilder 添加一個 stops()的擴展方法即可
fun Expression.InterpolatorBuilder.stops(stopList:Array<(Expression.ExpressionBuilder.() -> Unit)?>){
    stopList.forEach { stop ->
        stop?.let {
            apply(it)
        }
    }
}

//將以上的擴展方法作為參數傳入 構建 Expression的最后一個參數,
var colorExpression = Expression.interpolate{
                linear()
                lineProgress()
                stops(colorStops)
            }

//最后將 colorExpression 應用到構建lineLayer的 lineGradient(colorExpression) 作為參數即可,大功告成
mMapView.getMapboxMap().getStyle()?.addLayer(
                lineLayer(layerId, sourceId){
                    lineCap(LineCap.ROUND)
                    lineJoin(LineJoin.ROUND)
                    lineWidth(5.0)
                  lineGradient(colorExpression)
                }
            )

“Android基于Mapbox V10如何繪制LineGradient軌跡”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

海原县| 宜春市| 巴青县| 华宁县| 彝良县| 安达市| 永兴县| 融水| 灵璧县| 延长县| 青龙| 临清市| 平南县| 米泉市| 巴里| 乌拉特后旗| 南溪县| 平塘县| 棋牌| 德安县| 柘荣县| 德兴市| 绥滨县| 嘉善县| 铁岭市| 阿拉善左旗| 宿迁市| 朝阳区| 黎平县| 东港市| 雷波县| 葫芦岛市| 万载县| 广灵县| 宾阳县| 许昌市| 佛教| 象州县| 唐山市| 始兴县| 米林县|