Android自定义导览地图组件(一)

原创 cheny  2017-08-21 09:35  评论 0 条
摘要:

鉴于Android关于自定义导览地图的相关资料以及开源项目贫乏,应Android同行几位小伙伴们的建议,决定写下这篇文章分享给大家。由于博客篇幅限制,本文将分两到三篇博文叙述。

版权说明 : 《Android自定义导览地图组件(一)于当前乘月网CSDN博客属同一原创,转载请说明出处,谢谢。

 

         鉴于Android关于自定义导览地图的相关资料以及开源项目贫乏,应Android同行几位小伙伴们的建议,决定写下这篇文章分享给大家。由于博客篇幅限制,本文将分两到三篇博文叙述。
进入主题:

先看看下面的效果图:

可以看到,地图组件基本上实现当前主流地图应用(如百度,高德地图)的缩放拖拽移动以及定位图标等功能。

实现思路:
其实一开始想了很多方案:
1. 单纯的自定义一个View然后Draw绘制地图和定位图标,用各种分工逻辑类拆分单元实现。
2. 自定义View绘制地图+自定义View绘制定位图标,用各种分工逻辑类拆分单元实现。
3. 自定一个View,地图是View的背景图+ImageView作为定位图标。
4. 自定义ViewGroup+自定义Imageview作为地图+ImageView作为定位图标。
………….省略后面n种方案,真是绞尽脑汁
由于本文重点在于提供实现路线,最终敲定了最简单的第4种方案:自定义ViewGroup(MapContainer)+自定义ImageView(MapView)+ImageView(定位图标marker)。不过,通过本文的学习,上述其它方案的实现也就变得简单多了。

分析:
1. MapContainer提供地图和定位图标的盛放容器,定位图标可以叠加显示于地图之上。我们知道,地图的缩放(缩放会导致定位位置的改变)和移动,定位图标随之移动,作为ViewGroup肯定可以拿到这两种ImageView的对象,一边监听地图View----MapView的变化(获取变化值),再传递并控制地位图标View--marker的显示位置。
2. 为什么自定义ImageView?因为ImageView可以直接显示地图图片呗,但是缩放移动什么的还得靠自定义来实现。
3. 定位图标没什么难点,直接用ImageView显示坐标icon就好了,剩下的交给ViewGroup动态控制其位置就好了。
通过上述,总结下该方案:核心业务就在MapView上,MapContainer打辅助,定位图标ImageView打酱油。
对于一个图片可移动,缩放的功能实现,自然而然就能想到就是常见的查看大图嘛。
开干!!!

一、 自定义MapView
图片加载完成时,自动对图片进行自适应ViewGroup(或屏幕)缩放。
大多数情况下,图片分辨率都不会是刚好ViewGroup(或屏幕)大小,需要在图片加载时获取其真实显示尺寸并根据当前ViewGroup尺寸做自适应缩放以达到最佳的观感效果。
那么如何知道图片什么时候加载好了?这里可以实现ViewTreeObserver. OnGlobalLayoutListener接口来订阅监听布局变化。当前视图树中,全局布局发生改变或者某个视图的可视状态发生改变时,会得到消息推送(调用订阅者的OnGlobalLayoutListener下的onGlobalLayoutListener方法),图片加载完成后显示到屏幕上便会触发该方法,完整代码如下:

对于ImageView可缩放,需要设置:setScaleType(ScaleType.MATRIX)属性 ,初始化图片矩阵Matrix 对象以及设定三个缩放比例系数:

 

正如上述,onGlobalLayout()在很多情况下都会被触发,然而我们只需要确定一旦图片加载完成便对其自适应屏幕的缩放处理,所以我们需要一个Flag进行判定,并确定能够获取Drawable对象则表示图片刚好加载完成:

 

OK,检测到图片加载完成,便可以进行缩放处理。为了少点废话,接下来“代码+注释”为主:

折腾完自适应,开始折腾手势缩放,实现缩放手势探测器接口OnScaleGestureListener来完成图片随手势的动态缩放。初始化ScaleGestureDetector对象并重写当前View的onTouchEvent()方法,将touch事件交给ScaleGestureDetector处理:

接下来是处理onScale事件代码:

好了,写了那么多,上个图看看运行效果,舒缓下紧张的气氛:

还是有效果的,滋滋滋~  不过,这个白边还有图片中心缩放着缩放着就跑偏了着实让人强迫症大发。所以,应该在执行缩放前调用checkBoderAndCenter()方法用于检测并修复留白边,图片中心跑偏的问题:

效果图不贴了,节省写博时间。上图我们也可以看到:图片缩小到宽高小于View的宽高后,手指离开屏幕,此时图片无法自动恢复(放大)到自适应View宽高的大小,只能依靠手动缩放恢复,甚是心累。所以,需求来了…...缩放之后,检测这样的情况,再用一个动画让图片平滑恢复自适应View大小,接下来onScaleEnd登场:

好了,大工造成!来看看效果吧:

上面所述的留白,图片中心移位以及缩小后不能自动恢复自适应View(或屏幕)大小的问题在效果图中已经不复存在了,滋滋滋~

上文代码提到自动缩放任务AutoScaleTask,咱趁热打铁来实现双击缩放功能。一般查看地图(或大图)时,双击,如果当前缩放比例小于一级放大(scale<SCALE_MID)比例就自动放大到一级放大(SCALE_ MID), 如果比例大于等于一级放大(SCALE_ MID)比例且小于二级放大(SCALE_MAX)比例就自动放大到二级放大(SCALE_MAX),如果等于二级放大(SCALE_ MID)比例就缩小到自适应View大小(SCALE_ADAPTIVE),在自动缩放过程中不再响应双击事件,直到自动缩放结束,这就意味着需要一个flag进行锁定。思路已经很清晰,就差Android手势探测器GestureDetector帮我们判断双击手势。嗯,是这样!贴代码:

终于进入最后一个功能实现:手势移动。这里依然借助系统给我们算好的拖拽临界值ScaledTouchSlop决定是拖动图片。重写onTouchEvent()处理touch事件判断用户拖动(ActionMove)值是否达到临界值,是则从手势触点(Point)的中心点(因为可能不止一个手指在拖动,需要求中心点)出发移动图片:

好了,几经周折终于把查看大图的功能搞定了,这里就不贴效果图了,下一篇再见!

本文地址:http://icheny.cn/android%e8%87%aa%e5%ae%9a%e4%b9%89%e5%af%bc%e8%a7%88%e5%9c%b0%e5%9b%be%e7%bb%84%e4%bb%b6%e4%b8%80/
关注我们:加我微信:扫描二维码乘月网的微信号,微信号:ausboyue
版权声明:本文为原创文章,版权归 cheny 所有,欢迎分享本文,转载请保留出处!

发表评论


表情