最近开发需要加载地图,包括离线瓦片和在线地图,因为百度和高德要掏钱并且不支持加载自己的瓦片,想着有没有开源的替代呢?发现了osmdroid这个开源库可以加载地图,但是关于开发资料中文少的可怜,有关博客都是互相抄,找不到有用的信息,于是我狠下心看了遍源码,然后开始了填坑之旅。
首先加入依赖如下:
implementation 'org.osmdroid:osmdroid-android:6.1.11'
然后,在xml里加入组件:
<org.osmdroid.views.MapViewandroid:id="@+id/map"android:layout_width="match_parent"android:layout_height="match_parent" />
最后,在activity中开始加载map
mapView?.maxZoomLevel = 23.0mapView?.minZoomLevel = 0.0mapView?.controller?.setZoom(12.0)//让瓦片适应不同像素密度:默认地图显示的字体小,图片像素高,可设置以下代码,使地图适应不同像素密度,更美观mapView?.isTilesScaledToDpi = true//设置缩放按钮可见val zoomController = mapView?.getZoomController()zoomController?.setVisibility(CustomZoomButtonsController.Visibility.NEVER)mapView?.setMultiTouchControls(true) // 触控放大缩小mapView?.overlayManager?.tilesOverlay?.isEnabled = truemapView?.isSelected = truevar dm = resources.displayMetrics//指南针var mCompassOverlay = CompassOverlay(this, InternalCompassOrientationProvider(this),mapView)mCompassOverlay.enableCompass()mapView?.getOverlays()?.add(mCompassOverlay)//比例尺配置var mScaleBarOverlay = ScaleBarOverlay(mapView)mScaleBarOverlay.setScaleBarOffset(dm.widthPixels / 2, 10)mapView?.getOverlays()?.add(mScaleBarOverlay)mapView?.overlays?.add(mScaleBarOverlay)//定位var mLocationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(this), mapView)mapView?.overlays?.add(mLocationOverlay)mLocationOverlay.enableMyLocation()//地图移动到该点var startPoint = GeoPoint(GeoPoint(34.360284, 108.859602))mapView?.controller?.setCenter(startPoint)mapView?.setUseDataConnection(true)mapView?.setTileSource(tianDiTuCiaTileSource)
其中,tianDiTuCiaTileSource是地图的在线资源,我用的是天地图,也可以换成别的,只要url配置正确就可以。如下:
static String wz = "tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&tk=自己申请的token";//影像地图 _W是墨卡托投影 _c是国家2000的坐标系public static OnlineTileSourceBase tianDiTuImgTileSource = new XYTileSource("Tian Di Tu Img", 1, 18, 256, "",new String[]{"https://t0." + wz,"https://t1." + wz,"https://t2." + wz,"https://t3." + wz,"https://t4." + wz,"https://t5." + wz,"https://t6." + wz,"https://t7." + wz}) {@Overridepublic String getTileURLString(final long pMapTileIndex) {Log.d("url", getBaseUrl() + "&TILEROW=" + MapTileIndex.getY(pMapTileIndex) + "&TILECOL=" + MapTileIndex.getX(pMapTileIndex)+ "&TILEMATRIX=" + MapTileIndex.getZoom(pMapTileIndex));return getBaseUrl() + "&TILEROW=" + MapTileIndex.getY(pMapTileIndex) + "&TILECOL=" + MapTileIndex.getX(pMapTileIndex)+ "&TILEMATRIX=" + MapTileIndex.getZoom(pMapTileIndex);}};
把上面地址中的token换成自己申请的,就可以了
至此,在线地图就加载出来了。
接下来,我们来加载离线瓦片。
离线瓦片的格式有很多种,osm也支持好多,这里我用的是.zip瓦片文件,解压开里面是一张一张的图片,然后osm地图会根据你缩放的大小和坐标,找到对应的图片进行显示。废话不多说,代码是最好的老师,代码下:
fun mapViewOtherData(mapView: MapView, str: String) {//str是离线瓦片.zip的路径,Android10以上,如果路径没有权限,下面会报错。所以我的做法是,先把zip复制到自己的包名下的私有目录,然后随便进行操作val strFilepath = strval exitFile = File(strFilepath)if (!exitFile.exists()) { //文件不存在,用默认网络的} else { //文件存在try {//source 是zip解压后文件夹的名称,我zip文件名字和里面文件夹一样,所以代码这么写val source = exitFile.name.substring(0, exitFile.name.lastIndexOf("."))val archives = arrayOfNulls<IArchiveFile>(1)archives[0] = ArchiveFileFactory.getArchiveFile(exitFile)val customTiles = CustomTileSource(source,12,23,256,".png",)val providers = arrayOfNulls<MapTileModuleProviderBase>(1)providers[0] = MapTileFileArchiveProvider(SimpleRegisterReceiver(this),customTiles,archives)val tileProvider = MapTileProviderArray(customTiles,SimpleRegisterReceiver(this), providers)var tilesOverlay = TilesOverlay(tileProvider, this)tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT)mapView.getOverlayManager()?.add(tilesOverlay)return} catch (ex: Exception) {ex.printStackTrace()}Toast.makeText(this," did not have any files I can open!",Toast.LENGTH_LONG).show()}}
上面代码CustomTileSource是自定义的一个加载类,如下:
public class CustomTileSource extends BitmapTileSourceBase {public CustomTileSource(String aName, int aZoomMinLevel, int aZoomMaxLevel, int aTileSizePixels, String aImageFilenameEnding) {super(aName, aZoomMinLevel, aZoomMaxLevel, aTileSizePixels, aImageFilenameEnding);}
}
至此,osm离线瓦片也加载出来了。
osmdroid加载地图,确实很强大,官方的demo也有,但是demo里面没有加载zip的例子(吐槽一下,添加marker,画点线面的例子都有,就是没有zip),所以费了好大的功夫才把zip给加载出来。所以,记录一下。