关于 ArcGIS Runtime SDK for Android 10.2.9 中的地物点击事件

版权声明:本文为博主原创文章,转载请注明出处,如有问题,欢迎指正,谢谢。 https://blog.csdn.net/qq_33404903/article/details/88012377

目录

1.关于 onSingleTap(float x, float y) 方法

2.识别地图上的 marker graphic

3.识别地图上的 Geometry Feature

4.需要注意的点

1.点击事件之前

2.加载离线 .shp 文件

3. 处理 FeatureLayer 中没有要素的情况

4.居中地物

5.关于 Fragment 或者 Activity 中的 MapView


在 ArcGIS Runtime SDK for Android 10.2.9 中,并没有专门针对 marker 和其他地物点击事件监听,需要我们自己在为地图设置单击监听,并在 onSingleTap 方法中自己处理。

1.关于 onSingleTap(float x, float y) 方法

首先让持有 MapView 控件的 Activity 或者 Fragment 实现 OnSingleTapListener,需要注意的是该接口中的 onSingleTap(float x, float y) 中的 x、y 是屏幕坐标 x、y,如果你需要地图上的 Geometry 类型的 point ,可以使用下列方法来得到地图上的点:

Point mapPoint = mMapView.toMapPoint(x, y);

2.识别地图上的 marker graphic

在加载图层时,一般 marker (标识建筑或者地理位置的图片)是位于最上层的 GraphicsLayer 中,所以最先接收点击事件的应该是 marker,之后才是 FeatureLayer 等其他图层来处理。

在 GraphicsLayer 中,有一个方法来获取 Graphic 要素:

public Graphic getGraphic(int uid) {
    ...
}

那么我们首先要获取 uid 即 graphicId,通过如下方法:

    public int[] getGraphicIDs(float x, float y, int tolerance, int numberOfResults) {
        ...
    }

这里的 x、y 就是 screenPoint 的 x、y,tolerance 是识别所允许的容差,numberOfResults 是想要获取的结果数量,容差越大点击某点时可能获取的 Graphic 数量越多。

获取 GraphicId 具体的可以像下面这样操作:

    /**
     * 返回展示在屏幕点击位置的图形
     *
     * @param graphicsLayer 用来获取graphics ids 的 GraphicsLayer
     * @param x             点的x坐标
     * @param y             点的y坐标
     * @return 在 x y 位置上的 graphic
     */
    public int getTouchedGraphicId(GraphicsLayer graphicsLayer, float x, float y) {
        try {
            if (graphicsLayer == null) {
                Log.e(TAG, "getTouchedGraphicId: 请确认已加载图形层。");
                return -1;
            }
            // 获取 Point 附近的 graphics。
            int[] ids = graphicsLayer.getGraphicIDs(x, y, 10, 1);
            if (ids == null || ids.length == 0) {
                return -1;
            }
            return ids[0];
        } catch (Exception e) {
            Log.e(TAG, "getTouchedGraphicId: ", e);
        }
        return -1;
    }

若为识别出点击点对应的 Graphic,则返回 -1。

当你得到 GraphicId 后,你就可以居中或高亮这个 marker,或者取出 marker 中的信息来显示 popup  了。

使用如下方法来选中并高亮 graphic:

markersGraphicsLayer.setSelectedGraphics(new int[]{touchedGraphicId}, true);

3.识别地图上的 Geometry Feature

若点击事件未识别出对应的 marker ,则应该将点击事件交由下一层的 FeatureLayer 来处理,看是否可以识别点击位置对应的 Feature,进而获取该要素的信息。

类似于 graphicId, 这里的关键是 FeatureID。

在 FeatureLayer 类中,同样有获取 FeatureID 的方法:

public long[] getFeatureIDs(float x, float y, int tolerance, int numberOfResults) {
    ...
}

x、y为点击的 screenPoint 的坐标,tolerance 和 numberOfResults 是本次识别所允许的容差和希望得到的结果数量。

具体可以像下面这样操作:

    /**
     * 获取被点击的要素id
     *
     * @param featureLayer 要素图层
     * @param x            点击点的x坐标
     * @param y            y坐标
     * @return 点击要素图层获取到的要素id
     */
    public long getTouchedFeatureID(FeatureLayer featureLayer, float x, float y) {
        try {
            if (featureLayer == null) {
                Log.e(TAG, "getTouchedFeatureID: 请确认要素图层已加载--> " + featureLayer);
                return -1;
            }
            long[] featureIDs;
            featureIDs = featureLayer.getFeatureIDs(x, y, 10, 1);
            if (featureIDs != null && featureIDs.length > 0) {
                long featureID = featureIDs[0];
                Log.e(TAG, "getTouchedFeatureID: featureID--> " + featureID);
                return featureID;
            }
        } catch (Exception e) {
            Log.e(TAG, "getTouchedFeatureID: ", e);
        }
        return -1;
    }

得到要素id,就可以使用下里的方法来获取要素了:

public Feature getFeature(long oid) {
    ...
}

你也可以选中高亮或居中该要素,使用下列代码来选中并高亮要素:

featureLayer.selectFeature(featureId);

4.需要注意的点

1.点击事件之前

在处理有关地图单击事件的业务之前,应该先判断一下当前地图有没有正确加载:

        if (!mMapView.isLoaded()) {
            showErrorToast("地图尚未加载,无法操作,请确保本地已有离线地图数据");
            return;
        }

2.加载离线 .shp 文件

在实际操作中,FeatureLayer 一般是由离线 ShapeFile 文件(.shp文件)加载得来的,具体通过以下方式:

            // 从离线.shp文件中加载 ShapefileFeatureTable
            mShapeFileFeatureTable = new ShapefileFeatureTable(shapeFilePath);
            // 由 ShapeFileFeatureTable 来创建 FeatureLayer
            mFeatureLayer = new FeatureLayer(mShapeFileFeatureTable);
            // 创建图层颜色填充符号
            SimpleFillSymbol simpleFillSymbol = new SimpleFillSymbol(mColorForFeatureLayer);
            // 为要素层设置渲染器
            mFeatureLayer.setRenderer(new SimpleRenderer(simpleFillSymbol));
            // 将要素层添加到地图上
            mMapView.addLayer(mFeatureLayer);

3. 处理 FeatureLayer 中没有要素的情况

从离线文件中加载得来的 FeatureLayer 不一定都是有数据的,有可能对应的 FeatureTable 为空,所以在操作 FeatureLayer 之前,可以先判断一下,这个要素层中有没有数据,具体可以参考下面的方法:

    Envelope shpExtent = mShapeFileFeatureTable.getExtent();
            Log.e(TAG, "onSingleTap: shpExtent--> " + shpExtent);
            boolean hasGeoDataInShp = hasGeoDataInShp(shpExtent);
    if (hasGeoDataInShp){
        // dosomething
    }

    /** 
     * 在 shapeFile 中是否包含有地理数据
     * 经测试得知,当 extent 内容为 Envelope [m_envelope=Envelope2D [xmin=-1.0, ymin=-1.0, xmax=0.0, ymax=0.0], m_attributes=null]
     * 时,extent中没有任何数据
     *
     * @param shpExtent shapeFile的extent
     * @return shapeFile 中是否包含有地理数据
     */
    public boolean hasGeoDataInShp(Envelope shpExtent) {
        return shpExtent != null && !(shpExtent.getXMin() == -1.0
                && shpExtent.getYMin() == -1.0
                && shpExtent.getXMax() == 0.0
                && shpExtent.getYMax() == 0.0);
    }

该方法不一定适用于所有情况。

4.居中地物

居中地物具体可以参看如下方法:

    /**
     * 居中放大到期望的缩放级别
     *
     * @param centerPoint 中心点
     */
    private void zoomAndCenterToExpectedScale(Point centerPoint) {
        if (!mMapView.getMaxExtent().contains(centerPoint)) {
            Log.e(TAG, "zoomAndCenterToExpectedScale: x--> " + centerPoint.getX());
            Log.e(TAG, "zoomAndCenterToExpectedScale: y--> " + centerPoint.getY());
            showErrorToast("该点不在当前地图中");
            return;
        }
        double scale = mMapView.getScale();
        double v = getAutoCenterZoomScale();
        if (scale > v) {
            mMapView.zoomToScale(centerPoint, v);
            // mMapScaleView.refreshScaleView(v);
        } else {
            mMapView.centerAt(centerPoint, true);
        }
    }

其中的 getAutoCenterZoomScale() 方法获取的是居中地物时地图自动的缩放级别。

5.关于 Fragment 或者 Activity 中的 MapView

MapView 有一些方法来切换状态,具体你可在界面中这样处理:

    @Override
    public void onPause() {
        super.onPause();
        mMapView.pause();
    }

    @Override
    public void onResume() {
        super.onResume();
        mMapView.unpause();
    }

在 onDestroy() 方法中,释放地图资源:

    @Override
    public void onDestroy() {
        mMapView.removeAll();
        if (!mMapView.isRecycled()) {
            mMapView.recycle();
        }
        super.onDestroy();
    }

猜你喜欢

转载自blog.csdn.net/qq_33404903/article/details/88012377
今日推荐