Android基于Mapbox?V10?繪制LineGradient軌跡
前言
當(dāng)Mapbox升級到V10(我直接到當(dāng)前的最新V10.3)版本后,就可以就此實現(xiàn)自己想要實現(xiàn)的功能。
官方文檔 (docs.mapbox.com/android/map…)上的一些case就不在重復(fù)了
UISettings:
PreV10 通過MapView 拿到UISettings, 然后控制相關(guān)屬性,V10 UISettings已經(jīng)被移除了,不再統(tǒng)一管理,比較分散。
參見相關(guān)屬性的控制:
mMapView.compass.visibility = false mMapView.logo.enabled = false mMapView.attribution.enabled = false mMapView.gestures.updateSettings { null }//控制無法觸摸
PreV10 與 V10 的Camera 相關(guān)的animation (涉及到用到的Point,PreV10 之前有LatLn, Point 兩個類,當(dāng)時還覺得為啥弄兩個,比較冗余,V10里面拿掉了LatLn保留Point,注意的是Point構(gòu)造時 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 后的回調(diào) 需求時,傳入animationOptions給 easeTo(),如下實現(xiàn):
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 創(chuàng)建一個 LatlngBounds, 然后 getCenter(), V10中直接拿掉了 LatLngBounds, 也就沒有獲取List 對應(yīng)的 getCenter()了,沒有仔細地去找API是否有相對應(yīng)的替代,直接自己用擴展實現(xiàn)了一下:
@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 兩個點構(gòu)建 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設(shè)定Layer
V10 添加了DSL build 添加 source、layer,相對而言source、layer都比較集中在builder{}的 block里,實際應(yīng)用中通常source、layer 的添加都是分離的,動態(tài)的,通過sourceID, layerId 找到對應(yīng)的 source、layer然后修改里面的內(nèi)容, 發(fā)現(xiàn) addLayerBelow(layer, layId) 該方法不好使,Crash了,暫且不用它了。 SymbolLayer 相比之前的api接口,少了一個 style.addImages(imagesMap), 不再支持一次性添加多個Image,添加一個簡單的擴展函數(shù)即可。
fun Style.addImages(imageMap: Map<String, Bitmap>) { ? ?imageMap.forEach { (t, u) -> ? ? ? ?addImage(t, u) ? } }
創(chuàng)建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) ? }
添加對應(yīng)的 source, Layer
style.addSource( ? ? ? ? ? ? ? ?geoJsonSource(END_SOURCE_ID){ ? ? ? ? ? ? ? ? ? ?featureCollection(FeatureCollection.fromFeatures(markerCoordinates)) ? ? ? ? ? ? ? } ? ? ? ? ? ) ? style.addLayer(endSymbolLayer)
繪制軌跡LineLayer
同樣添加Layer前需要添加 source, List 構(gòu)建 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)); }
以上只需創(chuàng)建 Expression.Stop[] stops, 根據(jù)List 中每個Point 的配速對應(yīng)的色值,傳入即可,繪制LineGradient。
V10 中不再有 Expression 下 的Stop類,所以無從談起創(chuàng)建Stop[] 了,從官方的demo里看 , 最后跟了不定的 stop{}, 可以看見是一個可變參數(shù),所以打算構(gòu)建一個 stop{} 的數(shù)據(jù)。
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{} 的源碼如下, 所以需要提供一個高階函數(shù)的數(shù)組
? ?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) ? ? ? } ? } } ? //將以上的擴展方法作為參數(shù)傳入 構(gòu)建 Expression的最后一個參數(shù), var colorExpression = Expression.interpolate{ ? ? ? ? ? ? ? ?linear() ? ? ? ? ? ? ? ?lineProgress() ? ? ? ? ? ? ? ?stops(colorStops) ? ? ? ? ? } ? //最后將 colorExpression 應(yīng)用到構(gòu)建lineLayer的 lineGradient(colorExpression) 作為參數(shù)即可,大功告成 mMapView.getMapboxMap().getStyle()?.addLayer( ? ? ? ? ? ? ? ?lineLayer(layerId, sourceId){ ? ? ? ? ? ? ? ? ? ?lineCap(LineCap.ROUND) ? ? ? ? ? ? ? ? ? ?lineJoin(LineJoin.ROUND) ? ? ? ? ? ? ? ? ? ?lineWidth(5.0) ? ? ? ? ? ? ? ? ?lineGradient(colorExpression) ? ? ? ? ? ? ? } ? ? ? ? ? )
到此這篇關(guān)于Android基于Mapbox V10 繪制LineGradient軌跡的文章就介紹到這了,更多相關(guān)Android Mapbox 繪制 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 三種實現(xiàn)定時器詳解及實現(xiàn)方法
本文主要介紹 Android 定時器的知識資料,這里整理了三種方法來實現(xiàn)定時器的方法,有需要的小伙伴可以參考下2016-09-09Android Studio如何查看源碼并調(diào)試的方法步驟
這篇文章主要介紹了Android Studio如何查看源碼并調(diào)試的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Android Studio使用教程(五):Gradle命令詳解和導(dǎo)入第三方包
這篇文章主要介紹了Android Studio使用教程(五):Gradle命令詳解和導(dǎo)入第三方包,本文講解了導(dǎo)入Android Studio、Gradle常用命令等內(nèi)容,需要的朋友可以參考下2015-05-05為Android的apk應(yīng)用程序文件加殼以防止反編譯的教程
這篇文章主要介紹了為Android的apk應(yīng)用程序文件加殼以防止反編譯的教程,同時對apk程序的解殼操作也有詳細講解,需要的朋友可以參考下2016-04-04Android在一個app中安裝并卸載另一個app的示例代碼
這篇文章主要介紹了Android在一個app中安裝并卸載另一個app的示例代碼,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03