Android基于Mapbox V10 绘制LineGradient轨迹

目录
  • 前言
  • 普通的 camera
  • Style设定Layer
  • 绘制轨迹LineLayer

前言

当Mapbox升级到V10(我直接到当前的最新V10.3)版本后,就可以就此实现自己想要实现的功能。

官方文档 (docs.mapbox.com/android/map…)上的一些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轨迹的文章就介绍到这了,更多相关Android Mapbox 绘制 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mapbox gl开箱即用的地图引擎库

    目录 一.地图.地图.还是地图 二.什么是 mapbox-gl? 三.如何安装 四.基础使用:渲染地图 五.在地图上渲染区域 六.倾斜视角 七.旋转.跳跃.以及 Rap 一.地图.地图.还是地图 你总是需要地图,因为它过于直观. Ned 是一个前端开发,就职于一家 To C 业务的公司,这天产品经理提出了一个需求: “来一张地图吧,把我们所有的客户放在上面,让我们一眼就能看出来是谁在用我们的APP!” 从未做过地图的 Ned 茫然点了点头,开始进行技术筛选,然后他才发现,小小一张地图,居然有这么

  • mapboxgl实现带箭头轨迹线的代码

    最近在使用mapboxgl实现轨迹展示时,想实现类似高德地图导航轨迹效果,然而并未在网上找到类似示例.经一番研究与尝试,最终解决,效果如下. 添加箭头核心代码如下,只需在配置layout中添加symbol-placement和symbol-spacing属性即可: // 添加箭头图层 function addArrowlayer() { map.addLayer({ 'id': 'arrowLayer', 'type': 'symbol', 'source': { 'type': 'geojso

  • mapboxgl区划标签避让不遮盖实现的代码详解

    Mapbox GL JS是一个JavaScript库,使用WebGL渲染交互式矢量瓦片地图和栅格瓦片地图.WebGL渲染意味着高性能,MapboxGL能够渲染大量的地图要素,拥有流畅的交互以及动画效果.可以显示立体地图并且支持移动端,是一款十分优秀的WEB GIS开发框架. 常见的 mapbox.js和mapbox-gl.js的异同点?     相同点: 1.都是由Mapbox公司推出的免费开源的JavaScript库 2.都可以作为前端渲染矢量瓦片交互地图的工具 3.它们的样式设置都支持Map

  • Android Flutter绘制扇形图详解

    目录 简介 CustomPaint介绍 CustomPainter介绍 paint介绍 shouldRepaint介绍 示例 使用CustomPaint 自定义Painter 绘制 触摸事件处理 动画实现 简介 在开发过程中通常会遇到一些不规则的UI,比如不规则的线条,多边形,统计图表等等,用那些通用组件通过组合的方式无法进行实现,这就需要我们自己进行绘制.可以通过使用CuntomPaint组件并结合画笔CustomPainter去进行手动绘制各种图形. CustomPaint介绍 Custom

  • Android自定义View绘制贝塞尔曲线的方法

    本文实例为大家分享了Android自定义View绘制贝塞尔曲线的具体代码,供大家参考,具体内容如下 在平面内任选 3 个不共线的点,依次用线段连接. 在第一条线段上任选一个点 D.计算该点到线段起点的距离 AD,与该线段总长 AB 的比例. 根据上一步得到的比例,从第二条线段上找出对应的点 E,使得 AD:AB = BE:BC. 连接这两点 DE. 从新的线段 DE 上再次找出相同比例的点 F,使得 DF:DE = AD:AB = BE:BC. 到这里,我们就确定了贝塞尔曲线上的一个点 F.接下

  • Android Flutter利用CustomPaint绘制基本图形详解

    目录 绘制矩形 绘制圆形 绘制椭圆 绘制任意形状 绘制弧形 总结 上一篇我们介绍了 CustomPaint 的基本概念和使用,可以看到 CustomPaint 其实和 前端的 Canvas基本上是一样的,实际上前端 Canvas 支持的绘制方法 CustomPaint 都支持,毕竟 CustomPaint 其实也是基于 Canvas 实现的.本篇我们来介绍 CustomPaint 基本图形的绘制. 绘制矩形 绘制矩形比较简单,方法定义如下: void drawRect(Rect rect, Pa

  • Android自定义view绘制表格的方法

    本文实例为大家分享了Android自定义view绘制表格的具体代码,供大家参考,具体内容如下 先上效果图 平时很少有这样的表格需求,不过第一想法就是自定义view绘制表格,事实上我确实是用的canvas来绘制的,整个过程看似复杂,实为简单,计算好各个点的坐标后事情就完成一半了.不废话show code import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; imp

  • Android通过交互实现贝塞尔曲线的绘制

    目录 前言 获取触控位置 交互绘制实现 绘制代码 运行效果 总结 前言 之前几篇我们介绍了贝塞尔曲线的原理.绘制曲线和动效实现,这些都是代码预设好的,如果我们要根据需要自行绘制曲线,就需要使用交互来实现了.本篇我们先来介绍简单的交互式绘图,通过获取触控位置来设定贝塞尔曲线的控制点,从而实现交互式绘制曲线. 获取触控位置 第一个要解决的问题是如何获取手指在屏幕的触控位置.在 Flutter 中,提供了一个 Listener 组件,可以监听各类触控事件.Listener 的组件构造方法定义如下: c

  • Android基于Mapbox V10 绘制LineGradient轨迹

    目录 前言 普通的 camera Style设定Layer 绘制轨迹LineLayer 前言 当Mapbox升级到V10(我直接到当前的最新V10.3)版本后,就可以就此实现自己想要实现的功能. 官方文档 (docs.mapbox.com/android/map…)上的一些case就不在重复了 UISettings: PreV10 通过MapView 拿到UISettings, 然后控制相关属性,V10 UISettings已经被移除了,不再统一管理,比较分散. 参见相关属性的控制: mMapV

  • Android基于OpenGL在GLSurfaceView上绘制三角形及使用投影和相机视图方法示例

    本文实例讲述了Android基于OpenGL在GLSurfaceView上绘制三角形及使用投影和相机视图方法.分享给大家供大家参考,具体如下: 定义三角形 OpenGL 允许我们使用三维坐标来定义物体.在绘制三角形前,我们需要定义它各个点的坐标.我们一般使用数组来存储各个顶点的坐标. OpenGL ES 默认 [0,0,0] (X,Y,Z) 在GLSurfaceView的中心,[1,1,0]在右上角,[-1,-1,0]在左下角. 绘制三角形 在绘制三角形之前,我们必须告诉OpenGL我们正在使用

  • Android基于ImageView绘制的开关按钮效果示例

    本文实例讲述了Android基于ImageView绘制的开关按钮效果.分享给大家供大家参考,具体如下: 今天弄了一下用图片绘制开关按钮. 效果图: 还有我两张start图片和stop图片就是上面的图片,到时候大家可以按照自己的图片调用.. Main.xml文件 在xml进入这段代码就ok了. <ImageView Android:id="@+id/start" android:layout_width="150.px" android:layout_heigh

  • android绘制触点轨迹的代码

    本文实例为大家分享了android绘制触点轨迹的具体代码,供大家参考,具体内容如下 重点函数是onTouchEvent(),所有的触摸事件都会在View的这个函数里面处理 单点触控 单点触控的event是通过event.getAction()获得的,一般最少需要考虑下面这三种情况 MotionEvent.ACTION_DOWN: 手指 初次接触到屏幕 时触发. MotionEvent.ACTION_MOVE: 手指 在屏幕上滑动 时触发,会多次触发. MotionEvent.ACTION_UP:

  • Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果(推荐)

    了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一张图片中扫一下竟然能直接加好友,不可思议啊,那时候还不了解二维码,呵呵,然后做项目的时候,老板说要加上二维码扫描功能,然后自己的屁颠屁颠的去百度,google啥的,发现很多朋友都有介绍二维码扫描的功能,然后我就跟着人家的介绍自己搞起了二维码扫描功能,跟着人家的帖子,很快我的项目就加入了扫描二维码的功能,然后自己还很开心. 随着微信的到来,二维码越来越火爆,随处能看到二维码,比如商城里面,肯德基,餐厅等等,对于二维码

  • Android编程之canvas绘制各种图形(点,直线,弧,圆,椭圆,文字,矩形,多边形,曲线,圆角矩形)

    本文实例讲述了Android编程之canvas绘制各种图形的方法.分享给大家供大家参考,具体如下: 1.首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into

  • Android基于Sensor感应器获取重力感应加速度的方法

    本文实例讲述了Android基于Sensor感应器获取重力感应加速度的方法.分享给大家供大家参考,具体如下: FETC项目指导老师提出了新的需求,想要在游戏地图中表现出用户用户当期移动的方向,再用GPS的话显然很不靠谱,所以想到了android强大的感应器... 很多移动设备都内置了感应器,android通过Sensor和SensorManager类抽象了这些感应器,通过这些类可以使用android设备的传感器 一 介绍Sensor类 SDK只有一句介绍"Class representing a

  • Android基于Intent实现Activity之间数据传递的方法

    本文实例讲述了Android基于Intent实现Activity之间数据传递的方法.分享给大家供大家参考,具体如下: MainActivity: package com.test.intentdemo; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.Menu; import andro

  • Android基于OpenGL的GLSurfaceView创建一个Activity实现方法

    本文实例讲述了Android基于OpenGL的GLSurfaceView创建一个Activity实现方法.分享给大家供大家参考,具体如下: Android提供了两个基本的类让我们使用OpenGL ES API来创建和操纵图形:GLSurfaceView和 GLSurfaceView.Renderer.因此我们首先需要了解这两个类. 1. GLSurfaceView: 这是一个视图类,你可以调用OpenGL API在上面绘制图形和操纵物体,功能和SurfaceView相似.我们可以创建一个GLSu

  • Android 基于RecyclerView实现的歌词滚动自定义控件

    本文介绍了Android 基于RecyclerView实现的歌词滚动自定义控件,分享给大家,具体如下: 先来几张效果图: 这几天打算做一个控件,来让自己复习一下自定义 view 的知识以及事件分发机制的原理与应用.对于这个控件,我已经封装好了,只要调用就可以了. 本来是想放上 gitHub 和 添加依赖的.但是提交 github 出了问题一直不会弄,所以就只能先等等了.((:′⌒`)) 接下来说一下实现原理: 该控件分为以下几个部分: 歌词自动滚动 歌词颜色字体变化 触碰屏幕歌词不滚动,高亮显示

随机推荐