Android Osmdroid + 天地图 (二)

Osmdroid + 天地图 (二)

  • 前言
  • 正文
    • 一、定位监听
    • 二、改变地图中心
    • 三、添加Marker
    • 四、地图点击
    • 五、其他配置
      • ① 缩放控件
      • ② Marker更换图标
      • ③ 添加比例尺
      • ④ 添加指南针
      • ⑤ 添加经纬度网格线
      • ⑥ 启用旋转手势
      • ⑦ 添加小地图
    • 六、源码

前言

  上一篇中我们显示了地图,但是还不够,不满足基本的使用情况,本篇中继续进行功能使用上的完善。

在这里插入图片描述

正文

  本文中要实现定位和地图的交互功能,还有一些体验上的功能,首先我们先实现定位功能,意思就是一打开地图就定位到当前所在的位置。

一、定位监听

  Android实际上有自带的定位监听,位置准不准两说,起码是有的,下面我们来使用一下,在MainActivity中增加如下代码:

    private val TAG = "MainActivity"// 是否定位private var isLocation = false// 定位管理器private lateinit var locationManager: LocationManager

一个用于打印、一个用于控制是否定位,locationManager我们就在onCreate()函数中进行实例化,如下所示:

        // 创建位置管理器实例locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager

代码位置如下图所示

在这里插入图片描述

然后实现一个Android原生的定位监听,代码如下所示:

    private val locationListener = LocationListener { location -> // 处理位置变化val latitude = location.latitudeval longitude = location.longitudeLog.d(TAG, "onLocationChanged: $latitude, $longitude")}

然后我们可以写一个开始和停止定位的函数,代码如下所示:

    private var isLocation = falseprivate fun startLocation() {if (!isLocation){// 注册位置监听器locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0f, locationListener)isLocation = !isLocation}}private fun stopLocation() {if (isLocation) {// 停止位置更新locationManager.removeUpdates(locationListener)isLocation = !isLocation}}

你可能会发现,这行locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0f, locationListener)代码报错,我们看看源码是怎么样的

在这里插入图片描述
这里告诉我们调用这个方法需要在请求了定位权限之后,否则就会闪退,不信你可以试试看,而我们现在明显已经是获取了权限了,那么我们也可以增加一个注解,点击这一行,Alt + Enter,出现弹窗。

在这里插入图片描述

选择标注的这一项,则会在方法上方添加一个注解:@SuppressLint("MissingPermission"),这并不是最好的方式,但是省事,只要你满足那个前提,那就不会有问题,最后我们在initMap()函数中调用startLocation(),如下图所示

在这里插入图片描述

同时我们在定位监听回调中调用stopLocation(),如下图所示

在这里插入图片描述
下面我们运行一下看看是否会触发定位,看看控制台是否会打印经纬度。

在这里插入图片描述
打印了出来,这证明定位监听是有效的,下面我们需要改变地图中心。

二、改变地图中心

在MainActivity中增加一个函数,代码如下所示:

    /*** 修改地图中心点*/private fun changeMapCenter(geoPoint: GeoPoint) {Log.d(TAG, "changeMapCenter: $geoPoint")binding.mapView.apply {controller.apply {setZoom(14.0)setCenter(geoPoint)}}}

当调用changeMapCenter时,打印一下然后通过地图控制器修改缩放比例和地图中心,接下来就在定位监听中回调中调用changeMapCenter(),如下图所示:

在这里插入图片描述
下面运行一下,注意定位可能会有点慢,请耐心等待,只要定位成功了地图肯定会改变的,我们通过日志确认一下:

在这里插入图片描述
虽然我们改变了地图中心,但是没有标识,都不知道是哪里,下面就添加一个Marker。

三、添加Marker

首先在MainActivity中声明一个变量

    // 标记private var mMarker: Marker? = null

然后我们修改changeMapCenter()函数,添加代码如下所示:

            if (mMarker != null) {overlays.remove(mMarker)}mMarker = Marker(this).apply {title = "Marker"position = geoPoint}// 添加标点overlays.add(mMarker)

添加位置如下图所示:

在这里插入图片描述

此时你再运行一下就能看到一个标点了,我就不贴图了,容易暴露位置被Gank。

四、地图点击

下面我们来做一个地图点击事件,地图点击是在OverlayManager上完成的,我们回到initMap()函数,增加如下代码:

            // 覆盖管理器配置overlayManager.apply {tilesOverlay.isEnabled = trueadd(object : Overlay() {override fun onSingleTapConfirmed(e: MotionEvent?, mapView: MapView?): Boolean {Log.d(TAG, "onSingleTapConfirmed")return super.onSingleTapConfirmed(e, mapView)}})}

添加位置如下图所示:

在这里插入图片描述
从上述代码来看,我们启用地图上的图块叠加层,并添加一个新的叠加层,该叠加层在单击时打印日志,下面运行一下随便点击,看看控制台是否有日志打印。

在这里插入图片描述

出现了日志说明点击有效果,实际上还有一个方法,如下所示:

	override fun onSingleTapUp(e: MotionEvent?, mapView: MapView?): Boolean {Log.d(TAG, "onSingleTapUp")return super.onSingleTapUp(e, mapView)}

  这个函数也是单击,只不过我在测试的时候,同时打印时发现,每次点击这两个都会触发,而onSingleTapConfirmed()是最后触发的,所以就用onSingleTapConfirmed()了。现在点击生效之后,我们需要在点击之后改变地图位置,那么就可以调用changeMapCenter()函数,但是它需要传入一个GeoPoint对象,因此我们需要通过mapView去得到这个对象所需要的值,也就是经纬度,下面我们在onSingleTapConfirmed()回调中,增加如下所示代码:

	// 获取投影对象后进行坐标转换再切换地图中心位置mapView?.projection?.let { proj ->val geoPoint = proj.fromPixels(e!!.x.toInt(), e.y.toInt()) as GeoPointLog.d(TAG, "onSingleTapConfirmed: 切换地图中心位置")changeMapCenter(geoPoint)}

添加位置如下图所示:

在这里插入图片描述

这段代码的含义通过上面的注释应该都清楚了,再通俗一点,就是点击屏幕的像素进行x,y坐标的转换,下面再运行一下看看会怎么样?

在这里插入图片描述

看到这个日志地图就已经切换成功了。

五、其他配置

地图上还有一些其他的配置,比如我们可以显示缩放控件。

① 缩放控件

通过zoomController去控制显示的状态。

	zoomController.setVisibility(Visibility.SHOW_AND_FADEOUT)

比如这里我们设置为SHOW_AND_FADEOUT,就是淡入淡出,当你点击触摸屏幕时就会在底部出现,不触摸屏幕3.5s后控件消失,还有两个属性是ALWAYS, NEVER,很好理解就是总是显示和从不显示的意思,我们之前的代码中是设置从不显示的,你可以改成SHOW_AND_FADEOUT

② Marker更换图标

我们可以通过marker的属性去更改图标,首先我们画一个图标,在drawable下新建一个ic_marker.xml文件,代码如下所示:

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="48dp"android:height="48dp"android:tint="#5AD3E5"android:viewportWidth="24"android:viewportHeight="24"><pathandroid:fillColor="@android:color/white"android:pathData="M12,2L12,2C8.13,2 5,5.13 5,9c0,1.74 0.5,3.37 1.41,4.84c0.95,1.54 2.2,2.86 3.16,4.4c0.47,0.75 0.81,1.45 1.17,2.26C11,21.05 11.21,22 12,22h0c0.79,0 1,-0.95 1.25,-1.5c0.37,-0.81 0.7,-1.51 1.17,-2.26c0.96,-1.53 2.21,-2.85 3.16,-4.4C18.5,12.37 19,10.74 19,9C19,5.13 15.87,2 12,2zM12,11.75c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S13.38,11.75 12,11.75z" /></vector>

然后通过一行代码去设置,如下所示:

	icon = ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_marker)

位置如下图所示:

在这里插入图片描述

这样我们就替换掉了默认的那个Marker图标。

③ 添加比例尺

在地图上添加比例尺,在initMap()中,添加代码如下所示:

	add(ScaleBarOverlay(binding.mapView).apply {setAlignBottom(true) // 底部对齐setScaleBarOffset(100, 10) // 设置偏移量})

添加位置如下图所示:

在这里插入图片描述

这里的setAlignBottom()设置显示在屏幕底部,还有两个方法:setCentred()、setAlignRight(),根据方法名可以知道是什么意思,自行测试。

④ 添加指南针

添加指南针

	// 添加指南针add(CompassOverlay(this@MainActivity, binding.mapView).apply {enableCompass()})                

添加位置如下图所示:

在这里插入图片描述

⑤ 添加经纬度网格线

添加 显示纬度/经度网格线

	// 添加经纬度网格线add(LatLonGridlineOverlay2())

添加位置如下图所示:

在这里插入图片描述

⑥ 启用旋转手势

启用旋转手势需要配置地图和增加叠加层,地图上设置:

	setMultiTouchControls(true)

添加叠加层

	// 启用旋转手势add(RotationGestureOverlay(binding.mapView).apply { isEnabled = true })

添加位置如下图所示:

在这里插入图片描述

⑦ 添加小地图

通过小地图叠加层添加,根据屏幕的宽高 / 4设置小地图的宽高,并且设置小地图瓦片资源,代码如下所示:

	add(MinimapOverlay(this@MainActivity, binding.mapView.tileRequestCompleteHandler).apply {val dm = resources.displayMetricswidth = dm.widthPixels / 4height = dm.heightPixels / 4// 设置小地图资源setTileSource(Config.TDTCIA_W)})

添加位置如下图所示:

在这里插入图片描述
运行效果如下图所示:

在这里插入图片描述

六、源码

如果对你有所帮助的话,不妨欢迎StarFork

源码地址:OpenMap

APK下载地址:OpenMap1.0.apk

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/886250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS基础知识04

文本溢出通常是指在限定的空间内不能容纳所输入的文字&#xff0c;导致文字超出了容器的边界 一、文本溢出 1.1.css属性处理 所用到的属性 属性属性值overflowvisible&#xff1a;默认值&#xff0c;内容不会被修剪&#xff0c;会呈现在元素框之外。hidden&#xff1a;内容会…

gitlab和jenkins连接

一&#xff1a;jenkins 配置 安装gitlab插件 生成密钥 id_rsa 要上传到jenkins&#xff0c;id_rsa.pub要上传到gitlab cat /root/.ssh/id_rsa 复制查看的内容 可以看到已经成功创建出来了对于gitlab的认证凭据 二&#xff1a;配置gitlab cat /root/.ssh/id_rsa.pub 复制查…

Modbus TCP转Modbus ASCII解决方案

Modbus TCP和Modbus ASCII是两种不同的通信协议。Modbus TCP是一种二进制协议&#xff0c;Modbus ASCII是一种基于文本的协议。二者不能直接转换&#xff0c;因为它们的数据表示方式、消息结构、字符编码等都不相同。 如果你需要将Modbus TCP转换为Modbus ASCII&#xff0c;你…

十三、注解配置SpringMVC

文章目录 1. 创建初始化类&#xff0c;代替web.xml2. 创建SpringConfig配置类&#xff0c;代替spring的配置文件3. 创建WebConfig配置类&#xff0c;代替SpringMVC的配置文件4. 测试功能 1. 创建初始化类&#xff0c;代替web.xml 2. 创建SpringConfig配置类&#xff0c;代替spr…

全新升级!立迈胜STMP57系列防水一体化步进伺服电机:IP65+多圈绝对值编码器+EtherCAT通信+内置刹车

在这个科技日新月异的时代&#xff0c;每一步创新都意味着行业的一次飞跃。 回想当初&#xff0c;我们做防水电机的初衷只是因为客户的应用场景涉水&#xff0c;从而定做了IP65防护等级的一体式电机。 后来发现很多客户也有类似的需求&#xff0c;比如机械加工、户外照明、自…

5G CPE:为什么活动会场与商铺的网络成为最新选择

在快节奏的现代社会中&#xff0c;无论是举办一场盛大的活动还是经营一家繁忙的商铺&#xff0c;稳定的网络连接都是不可或缺的基石。然而&#xff0c;面对复杂的布线难题或高昂的商业宽带费用&#xff0c;许多场所往往陷入两难境地。幸运的是&#xff0c;5G CPE&#xff08;Cu…

React-redux 实战案例,自定义useSelector

创建一个新的 React 工程&#xff0c;并配置 Redux 和 Ant Design&#xff0c;你可以按以下步骤操作。我将使用 create-react-app 脚手架工具来快速创建一个基于 TypeScript 的 React 项目 1. 创建新项目 使用 create-react-app 创建一个新的 React 项目&#xff0c;带 TypeS…

【C++】list 类深度解析:探索双向链表的奇妙世界

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 如果你对string&#xff0c;vector还存在疑惑&#xff0c;欢迎阅读我之前的作品 &#xff1a; 之前文章&#x1f525;&#x1…

uniapp如何i18n国际化

1、正常情况下项目在代码生成的时候就已经有i18n的相关依赖&#xff0c;如果没有可以自行使用如下命令下载&#xff1a; npm install vue-i18n --save 2、创建相关文件 en文件下&#xff1a; zh文件下&#xff1a; index文件下&#xff1a; 3、在main.js中注册&#xff1a…

VScode-Java开发常用插件

中文——界面易读 字体主题——代码可观 头注释——项目信息明了 java开发包——java必备 git协作开发——版本控制

前端(3)——快速入门JaveScript

参考&#xff1a; 罗大富 JavaScript 教程 | 菜鸟教程 JavaScript 教程 1. JaveScript JavaScript 简称 JS JavaScript 是一种轻量级、解释型、面向对象的脚本语言。它主要被设计用于在网页上实现动态效果&#xff0c;增加用户与网页的交互性。作为一种客户端脚本语言&#…

FRP 实现内网穿透

如何通过 FRP 实现内网穿透&#xff1a;群晖 NAS 的 Gitea 和 GitLab 访问配置指南 在自建服务的过程中&#xff0c;经常会遇到内网访问受限的问题。本文将介绍如何利用 FRP&#xff08;Fast Reverse Proxy&#xff09;来实现内网穿透&#xff0c;以便在外网访问群晖 NAS 上的…

我们来学mysql -- EXPLAIN之select_type(原理篇)

EXPLAIN之select_type 题记select_type 题记 书接上文《 EXPLAIN之ID》2024美国大选已定&#xff0c;川普剑登上铁王座&#xff0c;在此过程中出谋划策的幕僚很重要&#xff0c;是他们决定了最终的执行计划在《查询成本之索引选择》中提到&#xff0c;explain的输出&#xff0…

uni-app快速入门(五)--判断运行环境及针对不同平台的条件编译

一、判断运行环境 在实际项目开发中&#xff0c;经常需要进行开发环境和生产环境的切换&#xff0c;uni-app可根据process.env.NODE_ENV判断当前运行环境是开发环境和生产环境&#xff0c;根据不同的环境调用不同的后台接口&#xff0c;具体实现方式: 在项目的static目录下建…

北京大学c++程序设计听课笔记101

基本概念 程序运行期间&#xff0c;每个函数都会占用一段连续的内存空间。而函数名就是该函数所占内存区域的起始地址&#xff08;也称“入口地址”&#xff09;。我们可以将函数的入口地址赋给一个指针变量&#xff0c;使该指针变量指向该函数。然后通过指针变量就可以调用这个…

构建客服知识库:企业效率提升的关键步骤

客服知识库是企业提升客户服务效率和质量的重要工具。它不仅帮助客服团队快速准确地回答客户问题&#xff0c;还能通过数据分析来优化服务流程和提升客户满意度。 1. 明确知识库的目标和范围 构建客服知识库的第一步是明确其目标和范围。这包括确定知识库的主要用户群体、需要…

Linux运维工程师推荐学习的开发语言

前言&#xff1a;会开发的运维和不会开发的运维可以说是两个世界的运维。 个人推荐python和go&#xff0c;前者可以做自动化运维&#xff0c;后者可以深挖k8s&#xff1b;最近就不先演示运维服务技术的部署和架构搭建了&#xff0c;在深挖自动化运维&#xff0c;为了让现在的工…

整合seata遇到的问题

自己遇到的问题&#xff0c;记录一下。 1、版本问题 我seata用的是1.7&#xff0c; 数据库驱动是 <dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.31</version><scope>…

从零到一:利用 AI 开发 iOS App 《震感》的编程之旅

在网上看到一篇关于使用AI开发的编程经历&#xff0c;分享给大家 作者是如何在没有 iOS 开发经验的情况下&#xff0c;借助 AI&#xff08;如 Claude 3 模型&#xff09;成功开发并发布《震感》iOS 应用。 正文开始 2022 年 11 月&#xff0c;ChatGPT 诞生并迅速引发全球关注。…

.netcore + postgis 保存地图围栏数据

一、数据库字段 字段类型选择(Type) 设置对象类型为&#xff1a;geometry 二、前端传递的Json格式转换 前端传递围栏的各个坐标点数据如下&#xff1a; {"AreaRange": [{"lat": 30.123456,"lng": 120.123456},{"lat": 30.123456…