ArcGIS Runtime 100定位类——LocationDisplay
其官方解释为:管理当前位置在显示地图里的展示,包括当前位置的信息,符号,以及随地图的平移、旋转、缩放等进行自动变化。
也就是有了这个类,不仅可以获取当前位置信息进行定位,也可以将位置信息展示出来。
api:
定位权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
直接上代码:
public class LocationActivity extends AppCompatActivity implements PermissionUtils.PermissionCallbacks {
private static final int REQUEST_PERMISSION_CODE = 0;
private MapView mMapView;
private LocationDisplay mLocationDisplay;
private String[] permissions = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
mMapView = (MapView) findViewById(R.id.mapview);
String theURLString = "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer";
ArcGISTiledLayer mainArcGISTiledLayer = new ArcGISTiledLayer(theURLString);
Basemap mainBasemap = new Basemap(mainArcGISTiledLayer);
ArcGISMap arcGISMap = new ArcGISMap(mainBasemap);
mMapView.setMap(arcGISMap);
if (PermissionUtils.hasPermissions(this, permissions)) {
startLocation();
} else {
PermissionUtils.requestPermissions(this, REQUEST_PERMISSION_CODE, permissions);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionUtils.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsAllGranted(int requestCode, List<String> perms, boolean isAllGranted) {
if (isAllGranted) {
startLocation();
}
}
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
}
private void startLocation() {
mLocationDisplay = mMapView.getLocationDisplay();
mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.RECENTER);
//当我们执行LocationDisplay.startAsync()方法时候,会在地图上显示出我们当前位置
mLocationDisplay.startAsync();
//获取的点是基于当前地图坐标系的点
Point point = mLocationDisplay.getMapLocation();
Log.e("xyh", "point: " + point.toString());
//获取基于GPS的位置信息
LocationDataSource.Location location = mLocationDisplay.getLocation();
//基于WGS84的经纬度坐标。
Point point1 = location.getPosition();
if (point1 != null) {
Log.e("xyh", "point1: " + point1.toString());
}
//如果要在LocationDisplay里进行位置信息的自动监听,方法也很简单,只需要LocationDisplay.addLocationChangedListener即可
mLocationDisplay.addLocationChangedListener(new LocationDisplay.LocationChangedListener() {
@Override
public void onLocationChanged(LocationDisplay.LocationChangedEvent locationChangedEvent) {
LocationDataSource.Location location = locationChangedEvent.getLocation();
Log.e("xyh", "onLocationChanged: " + location.getPosition().toString());
}
});
}
@Override
protected void onPause() {
super.onPause();
mMapView.pause();
}
@Override
protected void onResume() {
super.onResume();
mMapView.resume();
}
@Override
protected void onDestroy() {
super.onDestroy();
mMapView.dispose();
}
}
结束定位
if (mLocationDisplay.isStarted())
mLocationDisplay.stop();
位置监听的自动扫描模式
位置监听的自动扫描模式可能有点拗口,算是对于这个功能的直译吧。这个功能的意思是当你的位置信息变化时候,如何在地图上展示出来。
使用方法为:LocationDisplay.setAutoPanMode(LocationDisplay.AutoMode)。
模式一共有四种:
COMPASS_NAVIGATION 和NAVIGATION 分别最适用于步行导航和车载导航,用户的位置符号会固定显示在屏幕的某个点上,并且指向设备的顶部(也就是地图会随着用户移动而平移,随用户转弯而旋转);
OFF 模式,用户位置符号会随位置变化而移动,但地图不会动;
RECENTER模式,当用户位置处于当前地图范围内时候,用户位置符号会随位置变化而移动,但地图不会动;当用户位置处于地图边缘时候,地图会自动平移是用户的当前位置重新居于显示地图中心。
LocationDisplay类里可以直接设置位置符号样式
当我们执行LocationDisplay.startAsync()方法时候,会在地图上显示出我们当前位置,默认的符号如下所示:
如果我们想要改变这个符号样式,只需要重新设置符号即可,代码如下所示:
locationDisplay = mMapView.getLocationDisplay();
Resources resources=getResources();
BitmapDrawable bitmapDrawable= new BitmapDrawable(BitmapFactory.decodeResource(resources,R.drawable.location));
final PictureMarkerSymbol campsiteSymbol = new PictureMarkerSymbol(bitmapDrawable);
campsiteSymbol.loadAsync();
campsiteSymbol.addDoneLoadingListener(new Runnable() {
@Override
public void run() {
locationDisplay.setDefaultSymbol(campsiteSymbol);//设置默认符号
locationDisplay.setShowAccuracy(false);//隐藏符号的缓存区域
}
});
对于位置符号的设置有以下几种:
locationDisplay.setAcquiringSymbol(campsiteSymbol);//设置当前位置的填充符号
locationDisplay.setAccuracySymbol(campsiteSymbol);//设置最后一个已知位置的标记符号
locationDisplay.setPingAnimationSymbol(campsiteSymbol);//设置当前位置更新时候的动画
locationDisplay.setCourseSymbol(campsiteSymbol);//设置当前位置的路线符号
locationDisplay.setHeadingSymbol(campsiteSymbol);//设置当前位置设备面对方向的符号
locationDisplay.setDefaultSymbol(campsiteSymbol);//设置默认符号
位置符号隐藏
在ArcGIS Runtime 100里假如我们只是想获取位置信息,而不需要显示出来,我们只需要将位置监听的模式设置为OFF,然后执行以下代码即可。
locationDisplay.setShowLocation(false);//隐藏符号
locationDisplay.setShowAccuracy(false);//隐藏符号的缓存区域
locationDisplay.setShowPingAnimation(false);//隐藏位置更新的符号动画
PermissionUtils:
/**
* 动态申请权限工具类
* Created by xiaoyehai on 2018/4/25 0025.
*/
public class PermissionUtils {
public static final int GOTO_SEETING_CODE = 152;
/**
* 判断是否有权限
*
* @param context
* @param perms
* @return
*/
public static boolean hasPermissions(@NonNull Context context, @Size(min = 1) @NonNull String... perms) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (context == null) {
throw new IllegalArgumentException("Can't check permissions for null context");
}
for (String perm : perms) {
if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 申请权限
*/
public static void requestPermissions(@NonNull Activity activity, int requestCode, String[] permissions) {
List<String> permissionList = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(permission);
}
}
String[] permissionsArray = permissionList.toArray(new String[permissionList.size()]);//将List转为数组
if (permissionList.isEmpty()) {
//不可能为空
} else {
ActivityCompat.requestPermissions(activity, permissionsArray, requestCode);
//返回结果onRequestPermissionsResult
}
}
/**
* 申请权限的回调
*
* @param requestCode 请求权限时传入的请求码,用于区别是哪一次请求的
* @param permissions 所请求的所有权限的数组
* @param grantResults 权限授予结果,和 permissions 数组参数中的权限一一对应,元素值为两种情况,如下:
* 授予: PackageManager.PERMISSION_GRANTED
* 拒绝: PackageManager.PERMISSION_DENIED
*/
public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults, @NonNull PermissionCallbacks callBack) {
//授予的权限。
List<String> granted = new ArrayList<>();
//拒绝的权限
List<String> denied = new ArrayList<>();
for (int i = 0; i < permissions.length; i++) {
String perm = permissions[i];
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
granted.add(perm);
} else {
denied.add(perm);
}
}
if (null != callBack) {
if (denied.isEmpty()) {
callBack.onPermissionsAllGranted(requestCode, granted, denied.isEmpty());
}
if (!denied.isEmpty()) {
callBack.onPermissionsDenied(requestCode, denied);
}
}
}
/**
* 用户是否拒绝权限,并检查“不要提醒”。
*
* @param activity
* @param perms
* @return
*/
public static boolean somePermissionPermanentlyDenied(Activity activity, @NonNull List<String> perms) {
for (String deniedPermission : perms) {
if (permissionPermanentlyDenied(activity, deniedPermission)) {
return true;
}
}
return false;
}
public static boolean permissionPermanentlyDenied(Activity activity, @NonNull String perms) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(activity, perms)) {
return true;
}
return false;
}
public static void showDialogGoToAppSettting(final Activity activity) {
AlertDialog dialog = new AlertDialog.Builder(activity)
.setMessage("去设置界面开启权限")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// 跳转到应用设置界面
goToAppSetting(activity);
}
}).setCancelable(false).show();
}
/**
* 跳转到应用设置界面
*/
public static void goToAppSetting(Activity activity) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
intent.setData(uri);
activity.startActivityForResult(intent, GOTO_SEETING_CODE);
}
public static void showPermissionReason(final int requestCode, final Activity activity, final String[] permission, String s) {
AlertDialog dialog = new AlertDialog.Builder(activity)
.setMessage(s)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
requestPermissions(activity, requestCode, permission);
}
})
.setCancelable(false).show();
}
public interface PermissionCallbacks {
/**
* @param isAllGranted 是否全部同意
*/
void onPermissionsAllGranted(int requestCode, List<String> perms, boolean isAllGranted);
/**
*/
void onPermissionsDenied(int requestCode, List<String> perms);
}
}
下面来看看官方的例子
public class DisplayDeviceLocationActivity extends AppCompatActivity {
private MapView mMapView;
private LocationDisplay mLocationDisplay;
private Spinner mSpinner;
private int requestCode = 2;
String[] reqPermissions = new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_device_location);
mSpinner = (Spinner) findViewById(R.id.spinner);
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) {
// If LocationDisplay started OK, then continue.
if (dataSourceStatusChangedEvent.isStarted())
return;
// No error is reported, then continue.
if (dataSourceStatusChangedEvent.getError() == null)
return;
// If an error is found, handle the failure to start.
// Check permissions to see if failure may be due to lack of permissions.
boolean permissionCheck1 = ContextCompat.checkSelfPermission(DisplayDeviceLocationActivity.this, reqPermissions[0]) ==
PackageManager.PERMISSION_GRANTED;
boolean permissionCheck2 = ContextCompat.checkSelfPermission(DisplayDeviceLocationActivity.this, reqPermissions[1]) ==
PackageManager.PERMISSION_GRANTED;
if (!(permissionCheck1 && permissionCheck2)) {
ActivityCompat.requestPermissions(DisplayDeviceLocationActivity.this, reqPermissions, requestCode);
} else {
// Report other unknown failure types to the user - for example, location services may not
// be enabled on the device.
String message = String.format("Error in DataSourceStatusChangedListener: %s", dataSourceStatusChangedEvent
.getSource().getLocationDataSource().getError().getMessage());
Toast.makeText(DisplayDeviceLocationActivity.this, message, Toast.LENGTH_LONG).show();
// Update UI to reflect that the location display did not actually start
mSpinner.setSelection(0, true);
}
}
});
// Populate the list for the Location display options for the spinner's Adapter
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));
SpinnerAdapter adapter = new SpinnerAdapter(this, R.layout.spinner_layout, R.id.txt, list);
mSpinner.setAdapter(adapter);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0:
// Stop Location Display
if (mLocationDisplay.isStarted())
mLocationDisplay.stop();
break;
case 1:
// Start Location Display
if (!mLocationDisplay.isStarted())
mLocationDisplay.startAsync();
break;
case 2:
// RECENTER模式,当用户位置处于当前地图范围内时候,用户位置符号会随位置变化而移动,但地图不会动;
// 当用户位置处于地图边缘时候,地图会自动平移是用户的当前位置重新居于显示地图中心。
mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.RECENTER);
if (!mLocationDisplay.isStarted())
mLocationDisplay.startAsync();
break;
case 3:
// Start Navigation Mode
// 这种模式最适合于车载导航。
mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.NAVIGATION);
if (!mLocationDisplay.isStarted())
mLocationDisplay.startAsync();
break;
case 4:
// Start Compass Mode
// 这种模式更适合用户行走时的路标导航。
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) {
mLocationDisplay.startAsync();
} else {
Toast.makeText(DisplayDeviceLocationActivity.this, "权限被拒绝", Toast.LENGTH_SHORT).show();
mSpinner.setSelection(0, true);
}
}
@Override
protected void onPause() {
super.onPause();
mMapView.pause();
}
@Override
protected void onResume() {
super.onResume();
mMapView.resume();
}
@Override
protected void onDestroy() {
super.onDestroy();
mMapView.dispose();
}
}