Arcgis runtime for android mmpk加载图层组实现上下移动切换
Posted lwx2233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Arcgis runtime for android mmpk加载图层组实现上下移动切换相关的知识,希望对你有一定的参考价值。
目录
前言
最近单位在开发一个app,利用的是arcgis runtime for android去制作地图模块,它需要加载离线地图,并对每个图层进行identify操作,同时还要有一个图层操作的图层树(参考arcgis的layer),开发工具是android studio。
一、mmpk
mmpk是使用arcgis pro之中的一种切片格式,不同于tpk与vtpk,mmpk中保留了图层的属性,从代码层面来说,可以通过featurelayer的方式来对其中的图层进行读取。
二、加载mmpk并生成图层树
1.加载mmpk数据
arcgis runtime for android有专门的方法对mmpk数据进行读取,代码直接复制即可,android studio会自动检测错误并让你alt + enter修改(这就是使用android studio的好处)。
注意,这里新建了一个图层组(grouplayer)去对mmpk中的图层进行存放!
String mmpkPath = getExternalFilesDir(null) + "/xxx.mmpk";
MobileMapPackage mobileMapPackage = new MobileMapPackage(mmpkPath);
GroupLayer projectAreaGroupLayer = new GroupLayer();
projectAreaGroupLayer.setName("业务图层");
mobileMapPackage.loadAsync();
2.生成图层树
首先,需要使用mmpk加载完毕后的监听事件将图层逐个读取并存放到数组中,代码如下:
//layerName的集合
public static List LayerName = new ArrayList<>();
mobileMapPackage.addDoneLoadingListener(new Runnable()
@Override
public void run()
LoadStatus mainLoadStasus = mobileMapPackage.getLoadStatus();
if (mainLoadStasus == LoadStatus.LOADED)
List<ArcGISMap> mainArcGISMapL = mobileMapPackage.getMaps();
ArcGISMap mainArcGISMapMMPK = mainArcGISMapL.get(0);
LayerList mainMMPKLL = mainArcGISMapMMPK.getOperationalLayers();
int h = mainMMPKLL.toArray().length;
for (int i = 0; i < h; i++)
FeatureLayer mainFeatureLayer = (FeatureLayer) mainMMPKLL.get(0);
Log.d("mmpk当前加载的操作图层的名字", mainFeatureLayer.getName());
//将图层的名称存入数组中
LayerName.add(mainFeatureLayer.getName());
mainArcGISMapMMPK.getOperationalLayers().remove(0);
//往grouplayer中加载featurelayer
projectAreaGroupLayer.getLayers().add(mainFeatureLayer);
// add the group layer and other layers to the scene as operational layers
mainArcGISMap.getOperationalLayers().addAll(Arrays.asList(projectAreaGroupLayer));
Log.d("图层组的长度", String.valueOf(projectAreaGroupLayer.getLayers().toArray().length));
// zoom to the extent of the group layer when the child layers are loaded
ListenableList<Layer> layers = projectAreaGroupLayer.getLayers();
for (Layer childLayer : layers)
childLayer.addDoneLoadingListener(() ->
if (childLayer.getLoadStatus() == LoadStatus.LOADED)
mapView.setViewpoint(new Viewpoint(projectAreaGroupLayer.getFullExtent()));
);
setupRecyclerView(mainArcGISMap.getOperationalLayers());
else
Exception e = mobileMapPackage.getLoadError();
e.printStackTrace();
Toast.makeText(MainActivity.this, "加载失败!", Toast.LENGTH_LONG).show();
);
这里的layername是用来保存以后图层上下移动的参数,直接循环写入即可。
而setuprecyclerView是另一个方法,主要是用来调用官方网站的recyclerview的,具体如何构建这个官网上就有代码,方法的代码如下:
private void setupRecyclerView(List<Layer> layers)
mLayersAdapter = new LayersAdapter(this,this,MainActivity.this);
mLayersRecyclerView.setAdapter(mLayersAdapter);
for (Layer layer : layers)
// if layer can be shown in legend
if (layer.canShowInLegend())
layer.addDoneLoadingListener(() -> mLayersAdapter.addLayer(layer));
layer.loadAsync();
这里的mLayerAdapter是读取了LayerAdapter这个类,参照官网的recycleview例子,mLayerRecycleView则是用findViewId的方法读取了activity.xml中的layersRecyclerView控件,之后在某一个按钮处写了展示RecyclerView,代码如下:
//获取图层管理按钮
ImageButton layersButton = (ImageButton) findViewById(R.id.layersButton);
//添加图层管理按钮的点击事件
layersButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
if (mBottomSheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED)
// show bottom sheet
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
else
// hide bottom sheet
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
);
mBottomSheetBehavior便是从下面弹出的图层树,读取了BottomSheetBehavior这个类(在官网有)。
mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
最终效果如下:
三、identify功能
这个最简单了其实,只需要在mapview的点击事件中添加identify的功能即可,代码如下:
/点击地图时,判断下拉框是否存在,存在则关闭,不存在则identify
mapView.setOnTouchListener(new DefaultMapViewOnTouchListener(this, mapView)
@Override
public boolean onSingleTapConfirmed(MotionEvent v)
if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED)
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
else
android.graphics.Point screenPoint = new android.graphics.Point(Math.round(v.getX()), Math.round(v.getY()));
final Point clickPoint = mapView.screenToLocation(screenPoint);
//FeatureLayer从GroupLayer中获取,仅获取了一个图层,这里可能需要做图层筛选。
//由于上下移动的原因,图层的layer_index会变化,而这里没有变,所以需要重新筛选与控制
for(int i = 0;i<LayerName.size();i++)
if (Objects.equals(LayerName.get(i),current_layer_name))
current_layer_index = i;
//通过get后面的数字控制
FeatureLayer featureLayer = (FeatureLayer) projectAreaGroupLayer.getLayers().get(current_layer_index);
// FeatureLayer featureLayer=(FeatureLayer) mMapView.getMap().getOperationalLayers().get(0);
FeatureTable mTable = featureLayer.getFeatureTable();//得到查询属性表
int tolerance = 10;
double mapTolerance = tolerance * mapView.getUnitsPerDensityIndependentPixel();
Envelope envelope = new Envelope(clickPoint.getX() - mapTolerance, clickPoint.getY() - mapTolerance,
clickPoint.getX() + mapTolerance, clickPoint.getY() + mapTolerance, mapView.getSpatialReference());
QueryParameters query = new QueryParameters();
query.setGeometry(envelope);// 设置查询范围
final ListenableFuture<FeatureQueryResult> featureQueryResultFuture = featureLayer.selectFeaturesAsync(query, FeatureLayer.SelectionMode.NEW);
mCallout = mapView.getCallout();
featureQueryResultFuture.addDoneListener(new Runnable()
@Override
public void run()
try
if (mCallout.isShowing())
mCallout.dismiss();
FeatureQueryResult featureQueryResult2 = featureQueryResultFuture.get();
// create a textview to display field values
TextView calloutContent = new TextView(getApplicationContext());
calloutContent.setTextColor(Color.BLACK);
calloutContent.setSingleLine(false);
calloutContent.setVerticalScrollBarEnabled(true);
calloutContent.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
calloutContent.setMovementMethod(new ScrollingMovementMethod());
calloutContent.setLines(5);
Iterator<Feature> iterator = featureQueryResult2.iterator();
while (iterator.hasNext())
feature = iterator.next();
// create a Map of all available attributes as name value pairs
Map<String, Object> attr = feature.getAttributes();
Set<String> keys = attr.keySet();
calloutContent.append(key + ":" + value.toString() + "\\n");
// center the mapview on selected feature
Envelope envelope = feature.getGeometry().getExtent();
mapView.setViewpointGeometryAsync(envelope, 200);
// show callout
mCallout.setLocation(envelope.getCenter());
mCallout.setContent(calloutContent);
mCallout.show();
catch (Exception e1)
String error = "Select feature failed: " + e1.getMessage();
Toast.makeText(MainActivity.this, error, Toast.LENGTH_LONG).show();
);
return true;
);
这一段可能会少,粘的时候注意一下。
这里的current_layer_index是服务于图层上下移动的,记得先声明,它是通过读取LayerName这个集合,来判断图层的层级。
四、图层上下移动
思路是这样子的,先记录当前选中的图层layer的图层顺序x,然后将他删除,再次将他加载到x+1/x-1的图层顺序中,并调整Layername集合,保证每次移动图层时,layename与图层的layerlist相对应,从而实现了图层的上下移动。难点是需要理解grouplayer与layer的关系。
插句题外话,其实arcgis for js是有reorderlayer这个参数可以去调整图层的顺序,但是很遗憾runtime for android我没找到,所以只能用这种曲线救国的方式实现。
//声明实时更新layerName
List upDown_layer_name = MainActivity.LayerName;
//声明图层总数的下标
int layer_total_index = MainActivity.LayerName.size();
//图层上移,已完成
ivMoveUp.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
//声明判断图层是否为最高层级的参数,0代表否,1代表是
int is_highest_layer = 0;
//获取选中的图层的名称
Log.d("点击的itemView的名字", layer.getName());
//根据图层名称获取图层的层级(即加载顺序)
String MoveLayerName = layer.getName();
//获取该图层的下标
int layerIndex = 9999;
int layerIndexNext = 9999;
int LayerNameLength = layer_total_index;
System.out.println(LayerNameLength);
for (int i = 0; i < layer_total_index; i++)
//判断图层名与其中是否存在相同,相同则记录数组下标
if (Objects.equals(upDown_layer_name.get(i), MoveLayerName))
if (i < layer_total_index - 1)
layerIndex = i;
layerIndexNext = i + 1;
is_highest_layer = 0;
else
is_highest_layer = 1;
Toast.makeText(activity2, "该图层的层级已经是最低级别了!", Toast.LENGTH_LONG).show();
System.out.println(layerIndex);
System.out.println(layerIndexNext);
if (is_highest_layer == 0)
//这里对其进行修改
MapView mapView = activity2.findViewById(R.id.mapView);
GroupLayer groupLayer = (GroupLayer)mapView.getMap().getOperationalLayers().get(0);
//删除选中的图层
groupLayer.getLayers().remove(layerIndex);
//重新添加该图层,并使之上移
groupLayer.getLayers().add(layerIndexNext,layer);
upDown_layer_name.clear();
System.out.println("图层名称集合总数:" + MainActivity.LayerName.size());
System.out.println(upDown_layer_name.size());
System.out.println(layer_total_index);
//清空数组的同时,也将原始的数组的同时清除了
for (int i = 0;i <layer_total_index;i++)
String layer_name = groupLayer.getLayers().get(i).getName();
System.out.println(layer_name);
upDown_layer_name.add(layer_name);
System.out.println("图层名称集合总数:" + MainActivity.LayerName.size());
);
此处代码写在LayerAdapter这个类中,需要提前去传值,同时涉及不同类之间的layout调用,可以参考下面这个文章完善你的代码,完整代码我就不贴了太多了。
android 调用其他activity类中的方法_smalltree_it的博客-CSDN博客
总结
福至心灵想到的图层上下移动方法,花了一天在寻找看有没有参数直接改,没办法曲线救国两个钟出成果了,所以朋友们,绝知此事要躬行啊!
以上是关于Arcgis runtime for android mmpk加载图层组实现上下移动切换的主要内容,如果未能解决你的问题,请参考以下文章
Arcgis Runtime for andriod 100 加载geodatabase
Arcgis Runtime for andriod 100 加载TPK
Arcgis Runtime for andriod 100 Simple marker symbol
ArcGIS Runtime for Android 5 加载地图