ArcGIS for Android开发之MapView控件篇

本文深入解析了ArcGIS for Android中的MapView控件,包括获取和设置地图的比例尺、分辨率、中心点、范围,地图的缩放、平移和旋转,以及获取地图上某点的坐标。此外,还详细介绍了手势操作、状态改变事件监听、地图加载状态、地图背景设置等常用功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

ArcGIS for Android开发之MapView控件篇

ArcGIS for Android开发中,mapview扮演者很重要的角色,地图常见的操作有缩放、旋转、平移、获取范围、比例尺、分辨率等信息,以及常用的手势操作,以下是经常使用到的功能

1、获取/设置比例尺、分辨率、中心点、范围;

ArcGIS for Android中,MapView具有很多与地图操作有关的方法,其中,与地图的比例尺、分辨率、中心点、范围有关的方法如下:

获取/设置地图的中心点、范围、分辨率、比例尺

返回类型

方法

说明

Void

centerAt(Point centerPt, Boolean animated)

将地图居中到指定的点

Point

getCenter()

获取地图中心点

Polygon

getExtent()

获取地图最小外包矩形

Envelope

getMapBoundaryExtent()

获取地图的边界

Void

setExtent(Geometry geometry)

将地图放大到指定的范围,并将该geometrybound作为地图当前的extent

Void

setExtent(Geometry geometry, int padding)

将地图放大到指定的geometry以便geometry适应地图的bound

Double

getMaxResolution()

获取地图最大分辨率

Void

setMaxResolution(double maxResolution)

设置地图最大分辨率

Double

getMinResolution()

获取地图最小分辨率

Void

setMinResolution(double minResolution)

设置地图最小分辨率

Double

getResolution()

获取当前地图分辨率

Void

setResolution(double res)

设置当前地图分辨率

Double

getScale()

获取当前地图比例尺

Void

setScale(double scale)

设置当前地图比例尺

要获取/设置地图的比例尺、初始分辨率、范围、中心点等信息,直接使用上述方法即可,非常简单,在此不赘述,示例代码如下:

map.getCenter();//获取地图中心点;

map.getScale();//获取当前地图比例尺;

map.setScale(18489297.737236);//设置地图初始化时的比例尺;

map.setExtent(new Envelope(371987.18,252920.58, 624459.12, 423400.07));//范围;

map.setAllowRotationByPinch(true);//设置是否允许地图通过pinch方式旋转;

map.setRotationAngle(15.0);//设置地图的旋转角度;

……

2、地图缩放、平移和旋转;

与缩放和旋转有关的地图事件如下:

地图缩放、旋转

返回类型

方法

说明

Void

zoomin()

地图缩小

Void

zoomout()

地图放大

Void

zoomTo(Point centerPt, float factor)

将地图放荡到指定点

Void

zoomToResolution(Point centerPt, double res)

将地图放大到指定分辨率

Void

zoomToScale(Point centerPt, double scale)

将地图放大到指定比例尺

Double

getRotationAngle()

返回当前地图旋转角度(单位degree

Void

setRotationAngle(double degree)

将地图按照指定的角度(单位degree)旋转,度数为正数则按逆时针方向旋转

Void

setRotationAngle(double degree, float pivotX, float pivotY)

将地图按指定的点和角度旋转,角度为正数按逆时针

Void

setAllowRotationByPinch(boolean allowRotationByPinch)

允许/取消pinch旋转

Boolean

isAllowRotationByPinch()

是否允许pinch时旋转

 



2.1 平移

 

MapView 的方法中,没有专门针对平移操作,主要原因在于, MapView 中已经默认支持平移操作,即使用鼠标或手势拖动地图时就会平移地图,所以无需设置;

 



2.2 缩放至指定的分辨率/比例尺和连续放大n

 

一般的切片地图服务,在其 REST 服务的目录下都能查到切片的等级、等级对应的分辨率和比例尺,每个等级之间的分辨率和比例尺之间呈 2 倍的关系。
ArcGIS Android中没有像Web中的那种指针控件,没有直接的地图级别的控制,通常级别控制通过分辨率或比例尺来实现。可以用getResolution()getscale()方法获取当前地图的比例尺和分辨率,然后利用2的倍数关系,使用zoomTo()/zoomToScale()/zoomToResolution()来达到控制地图缩放级别的目的:

放大/缩小1倍:

map.zoomin()map.zoomout();

连续放大/缩小n倍:

map.zoomTo(point centerPt, float factor);如:map.zoomTo(centerPt2n),其中,n为放大或缩小的倍数;

map.zoomToScale(Point centerPt, double scale) ;如:map.zoomToScale(centerPtmap.getScale()/2n)/map.zoomToScale(ptmap.getScale()*2n),其中,n为放大或缩小的倍数;

map.zoomToResolution(point centerPt double res):map.zoomToResolution(centerPtmap.getResolution()/2n)/map.zoomToResolution(centerPtmap.getResolution() *2n),其中,n为放大或缩小的倍数;

zoomTopoint centerPt, float factor)中,centerPt指在哪个点放大,factor参数用来计算新的分辨率,计算公式为:新的分辨率 = 当前分辨率/factor。这个意思也就是说,想在当前分辨率下放大3倍,则新分辨率= 当前分辨率/23),因为每一级之间分辨率呈2的倍数关系,放大三级,分辨率就是23倍,factor =23 从上图中可以看出,地图级别每增加1级,分辨率/2,比例尺/2,故如果想将地图连续放大n级,factor =2n。如果想将地图连续缩小n级,则 factor =2-n

zooToScalePoint centerPt, double scale)和zoomToResolutionpoint centerPt double res)中,scaleres都指实际的分辨率和比例尺,故按照2的倍数关系直接乘除即可。

 



 

2.3 设置地图最大最小缩放级别

有时候我们需要设置地图放大或缩小到某个级别之后,不允许用户再放大或缩小,用以下两个方法很容易做到:

map.setMaxResolution(MaxResolution);

map.setMinResolution(MinResolution);

这两个方法设置了地图的最大、最小分辨率,也就限制了地图的缩放级别,当地图达到最大、最小分辨率时,地图将不能再被缩小或者放大,以免用户无限制的缩放地图或看到更多的内容。

在初始化时将地图设定为某种级别(找到该级别对应的分辨率、比例尺):

map.setResolution(该级别对应的分辨率);

至于如何获取当前地图等级,没办法,先获取resolution,然后去rest服务目录中对照取其级别吧。

 



2.4 旋转地图

可以使用setRotationAngledouble degree)和setRotationAngle(doubledegree, float pivotX, float pivotY)来实现将地图旋转一定的角度,要实现通过手势进行旋转,需要通过setOnPinchListener(OnPinchListener onPinchListener)监听来实现。如:

public void onCreate(Bundle savedInstanceState, OnPinchListener onPinchListener) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

 

map = (MapView)findViewById(R.id.map);

……

map.setAllowRotationByPinch(true); //是否允许使用Pinch方式旋转地图

map.setRotationAngle(15.0); //初始化时将地图旋转15度,参数为正时按逆时针方向旋转。

}

 



 



3、获取地图上某点的坐标

获取地图上某点的坐标主要使用下列几个方法,其中,主要使用toMapPoint()方法实现获取地图上的点坐标信息:

返回类型

方法

说明

SpatialReference

getSpatialReference()

返回地图的坐标系统

Point

toMapPoint(float screenx, float screeny)

将屏幕坐标转换成地图坐标系下的ArcGIS geometry Point坐标

Point

toMapPoint(Point src)

将屏幕坐标转换成地图坐标系下的ArcGIS geometry Point坐标

Point

toScreenPoint(Point src)

将地图坐标系下的ArcGIS geometry Point坐标转换成屏幕坐标

 



如,在长按地图时获取鼠标点的坐标代码如下:

// 长按显示鼠标点坐标及比例尺

this.map.setOnLongPressListener(new OnLongPressListener() {

private static final long serialVersionUID = 1L;

@Override

public void onLongPress(float x,float y) {

com.esri.core.geometry.Point pt = map.toMapPoint(x, y);

mapcenter.setText("X:"+ pt.getX() +"Y:"+ pt.getY());

labelxy.setText("当前地图分辨率为:" +map.getResolution());

mapscale.setText("当前地图比例尺为:" +map.getScale());

}

});

 

 

4、手势操作

默认情况下,MapView响应以下手势:

1)单一手指双击和pinch-out放大地图;

2)两个或多个手指pinch-in缩小地图;

3)单个手指拖拽平移地图。

其它手势监听有:

手势事件

返回类型

方法/事件监听

说明

OnLongPressListener

getOnLongPressListener()

获取地图长按事件监听

OnPanListener

getOnPanListener()

获取地图平移事件监听

OnPinchListener

getOnPinchListener()

获取地图捏夹事件监听

OnSingleTapListener

getOnSingleTapListener()

获取地图单击事件监听

OnZoomListener

getOnZoomListener()

获取缩放监听

void

setOnLongPressListener(OnLongPressListeneronLongPressListener)

设置地图长按事件监听

Void

setOnPanListener(OnPanListener onPanListener)

设置地图平移事件监听

Void

setOnPinchListener(OnPinchListener onPinchListener)

设置地图捏夹事件监听

Void

setOnSingleTapListener(OnSingleTapListeneronSingleTapListener)

设置地图单击事件监听

Void

setOnZoomListener(OnZoomListener onZoomListener)

设置缩放监听

       

 

5、关于地图显示不出来的问题

许多新手在使用ArcGIS RuntimeSDk for Android开发时,最简单的HelloWorld程序都会遇到问题,按照教程的步骤,添加了MapView,添加了切片图层,一切就绪,地图却始终出不来,遇到这个问题可先从以下几个方面查找原因:

1)如果添加了多个图层,请确保多个图层的地理参考一致;

2)是服务类型是否对应;

3)图层声明在xml布局文件中;

4)如果只是添加了一个底图图层仍然出不来底图,那么十有八九是extent的问题。首先,MapView控件必须至少包含一个图层,其次,该图层最好为其指定initExtent,在xml中代码如下:

 

android:id="@+id/map"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

initExtent="-20037507.0672, -30240971.9584, 20037507.0672, 30240971.9584">

 

 



initExtent在发布的服务中看到:有InitialExtent 和 FullExtent两个

取两个中的任一个,或者自定义一个包含于上述两个范围中的extent均可,推荐使用full extent

 



6、其它常用方法

除了上述提到的各种方法和监听之外,还有一些与地图相关的,也比较常用的方法和监听如下:

其它属性和事件

返回类型

方法/事件监听

说明

OnStatusChangedListener

getOnStatusChangedListener()

获取地图状态改变事件监听

Void

setOnStatusChangedListener(OnStatusChangedListeneronStatusChangedListener)

设置地图状态改变事件监听

Boolean

isLoaded()

MapView初始化之后返回true

Void

setEsriLogoVisible(Boolean visible)

打开或关闭地图上的ESRIlogo标签

Void

setMapBackground(int bkColor, int gridColor, float gridSize, float gridLineSize)

设置地图背景颜色

 

 

在论坛里看到一 "MapView和其它控件一起显示 " 的帖子, 那是很老的一帖子了, 很多朋友都说无法在android SDK 1.0上运行。既然那么多人关心,我在这里就把它重写一遍,顺便加入了一些新的功能 ,感兴趣的朋友可以看看。 第一步,当然是增加map的支持了。在Android Manifest.xml中增加以下语句: 第二步, 传说中的Layout: 然后, 创建一个MapViewActivity: public class MapViewActivity extends MapActivity { MapView mapView; MapController mapController; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); mapView = (MapView) findViewById(R.id.map); mapController = mapView.getController(); mapController.setZoom(15); updateView(); } @Override protected boolean isRouteDisplayed() { // TODO Auto-generated method stub return false; } private void updateView(){ Double lat = 31.23717*1E6; Double lng = 121.50811*1E6; GeoPoint point = new GeoPoint(lat.intValue(), lng.intValue()); mapController.setCenter(point); } } 好了,你的MapView上面就多了一个EditText了。 接着,我希望在MapView中增加ZoomIn和ZoomOut的功能(鄙视一下Google ,缺省的MapView居然连这个功能都没有) 1. 在我们的Layout中增加一段: 2. 在onCreate函数中增加: ViewGroup zoom=(ViewGroup)findViewById(R.id.zoom); zoom.addView(mapView.getZoomControls()); 现在在你的地图中点一下,屏幕左下角,是不是出现了一个Zoom Table? 这才是一个最基本的地图功能嘛。 以下技巧是基于SDK 1.0的) 一、申请Apikey,并放在正确的位置http://iceskysl.1sters.com/?action=show&id=441 这个应该都知道,但是是申请得到的key放哪里很多人不知道,可以放在 1、XML布局文件中 申请APIkey的时候,类似命令如下: C:\Documents and Settings\Administrator\Local Settings\Application Data\Android> "C:\Program Files\Java\jdk1.6.0_10\bin\keytool.exe" -list -alias androiddebugkey -keystore debug.keystore -storepass android -keypass android androiddebugkey, 2008-9-23, PrivateKeyEntry, 认证指纹 (MD5): 1D:68:43:7C:14:2E:CC:CA:35:8B:1F:93:A7:91:AD:45 2、java中 mMapView = new MapView(this, "01Yu9W3X3vbpYT3x33chPxxx7U1Z6jy8WYZXNFA"); 二、记得导入uses-library 由于1.0版本的修改,使得map包不再是默认的了,使用的时候需要在manifest中的application节点下加入 否则,你将遇到可恶的“java.lang.NoClassDefFoundError: ”,切记! 三、需要给予一定的权限 因为要使用GoogleMAP的service,所以需要 如果需要GPS等应用,还需要 四、Activity需要继承自MapActivity 类似如下代码; package com.iceskysl.showmap; import com.google.android.maps.MapActivity; import android.os.Bundle; public class ShowMap extends MapActivity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected boolean isRouteDisplayed() { // TODO Auto-generated method stub return false; } } 在Android中使用其提供的Sensor非常方便,如下是强制Landscape时候的情况: values[0]:方位角(水平旋转角),简单的说就是手机的头现在朝向哪个方位,0=北、90=东、180=南、270=西(可是好像不太准) values[1]:纵向旋转角,0=面朝上平置、-90=垂直向上、-180/180=面朝下平置、90=垂直向下 values[2]:橫向旋转角,0=朝前、90=往右倒、-90=往左倒 在Android中计算GPS两点间的距离/速度 Q:how to get distance between two GeoPoints in sdk 1.0 ? MapPoint.distanceSquared(MapPoint) is gone thaks!! A:you'll need to brush up on your trigonometry, and first compute the Haversine function (this is the standard way of doing it). In order to use the Java trig functions, you'll have to first convert all your angles from degrees to radians. Given two longitude/latitude pairs, and the earth's average radius (assume 6356.78km for your calculations), you can calculate the distance between the 2 points via this Java code: double EarthRad = 6356.78; // in km ! // first convert to radians... double geo1_lat = geo1.getLatitude()*java.lang.Math.PI/360; double geo1_lng = geo1.getLongitude()*java.lang.Math.PI/360; double geo2_lat = geo2.getLatitude()*java.lang.Math.PI/360; double geo2_lng = geo2.getLongitude()*java.lang.Math.PI/360; double deltaLat = java.lang.Math.abs(java.lang.Math.abs(geo2_lat) - java.lang.Math.abs(geo1_lat)); double deltaLng = java.lang.Math.abs(java.lang.Math.abs(geo2_lng) - java.lang.Math.abs(geo1_lng)); double dist = 2*EarthRad*java.lang.Math.asin(java.lang.Math.sqrt(haversine(deltaLat) + java.lang.Math.cos(pair1_lat) *java.lang.Math.cos(pair1_lng)*haversine(deltaLng))); Where "dist" now contains the distance between along the earth's surface. You can find the Haversine function trig equation by Googling it, then construct a method that returns the appropriate value. Computing the speed is straightforward: you know your sampling frequency, and you now know the distance between the most recent two points, so, employee speed = distance / sampling interval 参考:http://www.anddev.org/distance_between_two_geopoints_in_sdk10-t4195.html http://www.anddev.org/calculating_distance_between_two_gps_points-t3708.html 获得maps api的方法:本人的 打开Eclipse--->Windows--->Preferences--->Android--->Build 查看默认的debug keystore位置,我的是C:\Documents and Settings\Administrator\Local Settings\Application Data\Android\debug.keystore 启动命令行 直接 输入如下内容: keytool -list -alias androiddebugkey -keystore "C:\Documents and Settings\Administrator\Local Settings\Application Data\Android\debug.keystore" -storepass android -keypass android 结果如下:Microsoft Windows XP [版本 5.1.2600] (C) 版权所有 1985-2001 Microsoft Corp. C:\Documents and Settings\Administrator>keytool -list -alias androiddebugkey -ke ystore "C:\Documents and Settings\Administrator\Local Settings\Application Data\ Android\debug.keystore" -storepass android -keypass android androiddebugkey, 2009-3-12, keyEntry, 认证指纹 (MD5): 0F:C3:F0:C6:32:49:CE:C6:0E:18:57:CA:48:D7:CD:12 C:\Documents and Settings\Administrator> 屏幕图如下: 打开http://code.google.com/intl/zh-CN/android/maps-api-signup.html 填入你的认证指纹(MD5)即可获得apiKey了 0Ua9BENcUvNLXp8wn_vXXvVf70rLTYixrNxbHNQ http://www.androidcompetencycenter.com/category/android-api/ http://duzike.blogbus.com/logs/35386568.html http://www.helloandroid.com/node/206 http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351.html 根据输入城市名动态加载google地图 文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351.html 1)SendCityName.java: package com.google.android.citygmapview; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; public class SendCityName extends Activity { protected static final int REQUEST_SEND_DATA = 0; /** Called when the activity is first created. */ @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); getAndSendCityName(); } public void getAndSendCityName() { Button btn = (Button)findViewById(R.id.confirm); btn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { EditText edt=(EditText)SendCityName.this.findViewById(R.id.edt); Intent intent = new Intent(); intent.setClass(SendCityName.this, ShowGmapView.class); if(edt.getText().length()!= 0) { String data = edt.getText().toString(); String name="data"; intent.putExtra(name, data); startSubActivity(intent,REQUEST_SEND_DATA); } } }); } } 说明: if(edt.getText().length()!= 0)用来处理用户输入为空的情况,为空时数据不会传递到另外一个activity中去,节省资源。 (2)ShowGmapView.java: package com.google.android.citygmapview; import java.io.IOException; import java.util.Locale; import com.google.android.location.GmmGeocoder; import com.google.android.maps.MapActivity; import com.google.android.maps.MapController; import com.google.android.maps.MapView; import com.google.android.maps.Point; import android.location.Address; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.Menu.Item; public class ShowGmapView extends MapActivity { private static final int EXIT_ID = 0; private MapView myMapView; private Address[] maddrs; protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.gmap_view); Bundle extras = getIntent().getExtras(); String name="data"; if(extras != null) { String data1 = extras.getString(name); GmmGeocoder mgc = new GmmGeocoder(Locale.getDefault()); try { maddrs = mgc.query(data1, GmmGeocoder.QUERY_TYPE_LOCATION, 0, 0, 180.0, 360.0); if (null!=maddrs && maddrs.length > 0) { Log.d("CountryName: ", maddrs[0].getCountryName()); maddrs[0].getLatitude(); } else { setResult(RESULT_OK, null, extras); finish(); } } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } myMapView = new MapView(this); if(null!=maddrs && maddrs.length > 0) { Point p = new Point((int) (maddrs[0].getLatitude() * 1000000), (int) (maddrs[0].getLongitude() * 1000000)); /** 地图控制器 */ MapController mc = myMapView.getController(); mc.animateTo(p); /** 21是最zoom in的一级,一共是1-21级 */ mc.zoomTo(21); setContentView(myMapView); /** 切换到卫星地图 */ myMapView.toggleSatellite(); } setResult(RESULT_OK, null, extras); } } 文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351.html public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_I) { /** zoom in */ myMapView.getController().zoomTo(myMapView.getZoomLevel() + 1); return true; } else if (keyCode == KeyEvent.KEYCODE_O) { /** zoom out */ myMapView.getController().zoomTo(myMapView.getZoomLevel() - 1); return true; } else if (keyCode == KeyEvent.KEYCODE_S) { /** 卫星地图 */ myMapView.toggleSatellite(); return true; } else if (keyCode == KeyEvent.KEYCODE_T) { /** traffic,路况 */ myMapView.toggleTraffic(); return true; } return false; } 文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351_2.html @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, EXIT_ID, R.string.exit_gmap); return true; } @Override public boolean onMenuItemSelected(int featureId, Item item) { super.onMenuItemSelected(featureId, item); switch(item.getId()) { case EXIT_ID: finish(); break; } return true; } } 说明: 在开始设计时采用了Geocoder这个类,但似乎通过它获取的经纬度为空值,所以最后采取了GmmGeocoder,并能达到目的。 图示: (3)main.xml: (4)gmap_view.xml: (5)strings.xml: city gmap view confirm Exit google map (6)AndroidManifest.xml: 文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351_3.html
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值