本文主要讲解如何使用ArcGIS Runtime SDK for Android 在地图中显示移动设备的当前位置。
1.创建Android项目
2.添加Runtime SDK依赖 前两步本文省略,初学者可参照ArcGIS Runtime SDK for Android 学习笔记(1):第一个地图应用程序(二维)
3.添加权限及OpenGL ES支持
在AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.INTERNET" /><!--联网权限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><!--粗略定位权限-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><!--精确定位权限-->
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" /><!--OpenGL ES支持-->
注1:若移动设备Android版本为6.0及以上,不仅要在manifest中添加权限,还需要在Activity中代码动态获取权限。
注2:若使用Android模拟器AVD进行调试,需要设置模拟定位,步骤:
点击模拟器右侧工具栏的按钮,在出现的界面的Location选项卡中设置Longtitude及Latitude数值,之后点击“send”即可,注意经纬度为WGS84坐标系,若要进行坐标拾取,推荐使用谷歌地球获取。
4.设置界面布局
在layout中的布局XML中添加:
<!-- MapView控件 -->
<com.esri.arcgisruntime.mapping.view.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.esri.arcgisruntime.mapping.view.MapView>
<!-- 下拉框控件 -->
<Spinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/spinner"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="22dp"
android:background="#00000000"
android:popupBackground="#00000000"
android:overlapAnchor="false"/>
由于本例使用的Spinner下拉框比较特殊,列表项是由文字和图片组成,因此需要设置下拉框的布局,在layout中的布局XML中添加spinner_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:textColor="#FFF"
android:textSize="20sp"
android:gravity="end"
android:textStyle="bold|normal"
android:layout_weight="0.9"/>
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_weight="0.1"
android:contentDescription="@null"/>
</LinearLayout>
5.Spinner图片素材准备,准备了各个按钮的适用不同分辨率的图像:
下载地址:https://download.csdn.net/download/smart3s/10541268
6.编写代码:
(1)Spinner扩展:
ItemData.java:Spinner下拉框项变量,储存操作名称和图片ID
public class ItemData {
private final String text;
private final Integer imageId;
public ItemData(String text, Integer imageId) {
this.text = text;
this.imageId = imageId;
}
public String getText() {
return text;
}
public Integer getImageId() {
return imageId;
}
}
SpinnerAdapter.java:下拉框适配器变量,用来控制Spinner的显示
public class SpinnerAdapter extends ArrayAdapter<ItemData> {
private final int groupid;
private final ArrayList<ItemData> list;
private final LayoutInflater inflater;
public SpinnerAdapter(Activity context, int groupid, int id, ArrayList<ItemData>
list) {
super(context, id, list);
this.list = list;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.groupid = groupid;
}
public View getView(int position, View convertView, ViewGroup parent) {
View itemView = inflater.inflate(groupid, parent, false);
ImageView imageView = (ImageView) itemView.findViewById(R.id.img);
imageView.setImageResource(list.get(position).getImageId());
TextView textView = (TextView) itemView.findViewById(R.id.txt);
textView.setText(list.get(position).getText());
return itemView;
}
public View getDropDownView(int position, View convertView, ViewGroup
parent) {
return getView(position, convertView, parent);
}
}
(2)MainActivity.java:
变量准备:
//MapView控件变量
private MapView mMapView;
//位置显示变量
private LocationDisplay mLocationDisplay;
//下拉框变量
private Spinner mSpinner;
//若系统环境为Android6.0及以上版本,仅在manifest中添加权限是不够的,需要代码动态获取权限
//权限请求码
private int requestCode = 2;
//权限名称
String[] reqPermissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission
.ACCESS_COARSE_LOCATION};
onCreate方法:
// 定位按钮列表
mSpinner = (Spinner) findViewById(R.id.spinner);
// 从布局中获取MapView,并使用影像作为底图
mMapView = (MapView) findViewById(R.id.mapView);
ArcGISMap mMap = new ArcGISMap(Basemap.createImagery());
mMapView.setMap(mMap);
//获取定位组件类
mLocationDisplay = mMapView.getLocationDisplay();
// 设置位置改变监听
mLocationDisplay.addDataSourceStatusChangedListener(new LocationDisplay.DataSourceStatusChangedListener() {
@Override
public void onStatusChanged(LocationDisplay.DataSourceStatusChangedEvent dataSourceStatusChangedEvent) {
// 如果LocationDisplay启动OK,则继续。
if (dataSourceStatusChangedEvent.isStarted()){
return;
}
// 没有错误报告,然后继续。
if (dataSourceStatusChangedEvent.getError() == null){
return;
}
// 如果发现错误,处理启动失败。
// 检查权限,看看是否失败可能是由于缺乏权限。
boolean permissionCheck1 = ContextCompat.checkSelfPermission(MainActivity.this, reqPermissions[0]) ==
PackageManager.PERMISSION_GRANTED;
boolean permissionCheck2 = ContextCompat.checkSelfPermission(MainActivity.this, reqPermissions[1]) ==
PackageManager.PERMISSION_GRANTED;
if (!(permissionCheck1 && permissionCheck2)) {
// 如果权限尚未授予,请向用户请求权限。
ActivityCompat.requestPermissions(MainActivity.this, reqPermissions, requestCode);
} else {
// 向用户报告其他未知的故障类型—例如,在设备上可能无法启用位置服务。
String message = String.format("Error in DataSourceStatusChangedListener: %s", dataSourceStatusChangedEvent
.getSource().getLocationDataSource().getError().getMessage());
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
// 更新UI以反映位置显示,实际上没有启动
mSpinner.setSelection(0, true);
}
}
});
// 设置位置按钮列表
ArrayList<ItemData> list = new ArrayList<>();
list.add(new ItemData("Stop", R.drawable.locationdisplaydisabled));
list.add(new ItemData("On", R.drawable.locationdisplayon));
list.add(new ItemData("Re-Center", R.drawable.locationdisplayrecenter));
list.add(new ItemData("Navigation", R.drawable.locationdisplaynavigation));
list.add(new ItemData("Compass", R.drawable.locationdisplayheading));
//创建并绑定Spinner适配器
SpinnerAdapter adapter = new SpinnerAdapter(this, R.layout.spinner_layout, R.id.txt, list);
mSpinner.setAdapter(adapter);
//Spinner点击事件
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0:
// 停止显示位置
if (mLocationDisplay.isStarted())
mLocationDisplay.stop();
break;
case 1:
// 开始显示位置
if (!mLocationDisplay.isStarted())
mLocationDisplay.startAsync();
break;
case 2:
// 底图地图显示到中心
mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.RECENTER);
if (!mLocationDisplay.isStarted())
mLocationDisplay.startAsync();
break;
case 3:
// 开始导航模式(此模式,最佳适用于驾车导航)
mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.NAVIGATION);
if (!mLocationDisplay.isStarted())
mLocationDisplay.startAsync();
break;
case 4:
// 开始罗盘模式(此模式最佳适用于用户步行时的路径导航)
mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.COMPASS_NAVIGATION);
if (!mLocationDisplay.isStarted())
mLocationDisplay.startAsync();
break;
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) { }
});
其他:
//当接收到权限请求回调时调用
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
// 如果请求被拒绝,结果数组是空值
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 位置被授予许可。这可能是由于未能启动该系统而引发的。
// LocationDisplay,再次定位
mLocationDisplay.startAsync();
} else {
// 如果被拒绝,显示toast以告知用户所选择的内容。如果LocationDisplay再次启动,请求权限UX将被再次显示,选项应该被显示以允许不再显示UX。
// 另一种方法是禁用功能,因此请求不再显示
Toast.makeText(MainActivity.this, getResources().getString(R.string.location_permission_denied), Toast
.LENGTH_SHORT).show();
// 更新UI以反映位置显示,实际上没有启动
mSpinner.setSelection(0, true);
}
}
7.运行App可以进行简单的定位的相关操作: