《ArcGIS Runtime SDK for Android开发笔记》——离在线一体化技术:离线矢量数据编辑

1、前言

在上一篇我们已经实现了离线地理数据库的下载,这一篇我们着重介绍离线数据库的加载与编辑。

由于ArcGIS Runtime SDK for Android 10.2.X版本并没提供要素绘制功能,所以本篇中的要素绘制部分基于之前开源的Drawtools3.0工具实现。

本DEMO主要实现了:离线地理数据库加载、要素样式模板加载,要素新建、要素选择并开启编辑状态、要素删除等操作。由于内容较多涉及编辑部分仅详细介绍对Geodatabase的要素添加、要素删除、要素更新部分,其余请自行查阅源代码。

转载请注明出处:http://www.cnblogs.com/gis-luq/p/5858055.html 

2、离线要素编辑实现过程

2.1、加载本地离线要素

ArcGIS Runtime SDK for Android中提供了具体的Geodatabase类和FeatureLayer图层来加载.geodatabase文件,常用的类包括Geodatabase、GeodatabaseFeatureTable、GeodatabaseFeature、GeodatabaseFeatureServiceTable等,分别用来打开geodatabase数据文件、获取要素图层、获取图层中的具体要素,以及获取在线的要素服务。具体来讲,加载.geodatabase文件的步骤有如下几步:

1、  实例化一个Geodatabase对象,这个类有两个构造函数,都需要指定本地数据库的存储路径;

2、  创建一个GeodatabaseFeatureTable对象实例,用来获取需要的图层;

3、  创建一个FeatureLayer来存储获取的图层,并将获取的图层加载到地图中;

4、  调用dispose()方式释放资源。

复制代码
 /**
     * 读取Geodatabase中离线地图信息
     * @param geodatabsePath 离线Geodatabase文件路径
     */
    private void addFeatureLayer(String geodatabsePath) {

        Geodatabase localGdb = null;
        try {
            localGdb = new Geodatabase(geodatabsePath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        layerList = new ArrayList<>();
        // 添加FeatureLayer到MapView中
        if (localGdb != null) {
            for (GeodatabaseFeatureTable gdbFeatureTable : localGdb.getGeodatabaseTables()) {
                if (gdbFeatureTable.hasGeometry()){
                    FeatureLayer layer = new FeatureLayer(gdbFeatureTable);
                    mMapView.addLayer(layer);
                }
            }
        }
    }
复制代码

2.2、加载本地要素样式模板

    

绘制要素时往往会需要知道待绘制要素的图层名称以及要素的符号化样式,这里我们以geodatabse中的FeatureLayer为例演示要素样式模板获取流程。

复制代码
   /**
     * 添加要素绘制样式模板
     * 获取图层要素模板并添加到featureTempleteView
     * @param layer
     */
    private void addFeatureTemplate(FeatureLayer layer) {
        List<FeatureTemplate> featureTemp = ((GeodatabaseFeatureTable) layer.getFeatureTable()).getFeatureTemplates();
        for (FeatureTemplate featureTemplate : featureTemp) {
            GeodatabaseFeature g = null;
            try {
                g = ((GeodatabaseFeatureTable) layer.getFeatureTable()).createFeatureWithTemplate(featureTemplate, null);
                Renderer renderer = layer.getRenderer();
                Symbol symbol = renderer.getSymbol(g);
                float scale = context.getResources().getDisplayMetrics().density;
                int widthInPixels = (int) (35 * scale + 0.5f);
                Bitmap bitmap = SymbolHelper.getLegendImage(symbol, widthInPixels, widthInPixels);

                //将要素样式模板赋值给imgButton
                ImageButton imageButton = new ImageButton(context);
                imageButton.setImageBitmap(bitmap);
                imageButton.setTag(layer);//保存当前待编辑图层
                ((LinearLayout)featureTempleteView).addView(imageButton);//添加到要素样式模板列表
                imageButton.setOnClickListener(new ImageButtonOnClickListener());
            } catch (TableException e) {
                e.printStackTrace();
                Toast.makeText(MainActivity.this, "Error:" + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
            }
        }
    }
复制代码

2.2、编辑本地离线要素

要素编辑最核心的是FeatureTable中的增删改方法,通过这些方法可以实现本地数据库中要素编辑操作。

FeatureTable中的常用方法如下:

2.2.1、要素添加

复制代码
private FeatureLayer selectFeatureLayer;//当前选中图层
private Graphic selectGraphic = null;//待添加要素(零时图层中获取)
try {
    GeodatabaseFeatureTable geodatabaseFeatureTable = (GeodatabaseFeatureTable)selectFeatureLayer.getFeatureTable();
    GeodatabaseFeature gdbFeature = new GeodatabaseFeature(null, selectGraphic.getGeometry(), geodatabaseFeatureTable);
    long fid = geodatabaseFeatureTable.addFeature(gdbFeature);// 添加要素
    Log.d(TAG,"要素添加成功,Feature ID:"+fid);
} catch (TableException e) {
    e.printStackTrace();
}
复制代码

2.2.2、要素删除

复制代码
private FeatureLayer selectFeatureLayer;//当前选中图层
private Feature selectFeature = null;//当前选中要素
GeodatabaseFeatureTable geodatabaseFeatureTable = (GeodatabaseFeatureTable)selectFeatureLayer.getFeatureTable();
try {
   if (selectFeature!=null){
       eodatabaseFeatureTable.deleteFeature(selectFeature.getId());//删除要素
   }
} catch (TableException e) {
    e.printStackTrace();
}
复制代码

2.2.3、要素矢量信息更新

复制代码
private FeatureLayer selectFeatureLayer;//当前选中图层
private Feature selectFeature = null;//当前选中要素
private Graphic selectGraphic = null;//待更新要素(零时图层中获取)
try {
    GeodatabaseFeatureTable geodatabaseFeatureTable = (GeodatabaseFeatureTable)selectFeatureLayer.getFeatureTable();
    geodatabaseFeatureTable.updateFeature(selectFeature.getId(),selectGraphic.getGeometry());//更新要素
    Log.d(TAG,"要素更新成功");
} catch (TableException e) {
    e.printStackTrace();
}
复制代码

扩展说明:如何选中要素,以及如何处理具有压盖关系的要素选择问题?

针对这两个问题我们一并处理,首先扩展MapOnTouchListener类,实现长按出现放大镜,并选中要素。选中要素时我们采用遍历当前所有图层的方式,找出每个图层中第一个被选中的要素,然后弹窗提示供用户选择。

复制代码
//全局定义信息
private List<FeatureLayer> layerList;//矢量图层列表
private GraphicsLayer graphicsLayer = null;//零时图层
private FeatureLayer selectFeatureLayer;//当前选中图层
private Graphic selectGraphic = null;//当前选中要素(零时图层)
private Feature selectFeature = null;//当前选中要素
复制代码

要素选中扩展事件。

复制代码
/**
 * 地图窗口默认Touch事件
 * 支持长按放大镜选种要素
 */
public class MapSelectFeatureOnTouchListener extends MapOnTouchListener{

    public MapSelectFeatureOnTouchListener(Context context, MapView view) {
        super(context, view);
    }

    @Override
    public boolean onLongPressUp(MotionEvent point) {
        handleTap(point);
        //长按放大镜选择事件
        super.onLongPressUp(point);
        return true;
    }

    @Override
    public boolean onSingleTap(final MotionEvent e) {
        //单击响应事件
        return true;
    }

    /**
     * 获取当前选中要素
     * @param point
     */
    private void handleTap(MotionEvent point) {
        MotionEvent screePoint = point;

        //选中图层信息
        final List<SelectFeatureInfo> selectFeatureInfoList = new ArrayList<>();
        //记录当前选中要素信息,涉及多个图层情况
        for (int i=0;i<layerList.size();i++){
            FeatureLayer featureLayer = layerList.get(i);
            featureLayer.setSelectionColor(Color.YELLOW);
            featureLayer.setSelectionColorWidth(10);
            long[] selids = featureLayer.getFeatureIDs(screePoint.getX(), screePoint.getY(), 1);
            if (selids.length >= 1) {
                SelectFeatureInfo selectFeatureInfo = new SelectFeatureInfo();
                selectFeatureInfo.featureLayer = featureLayer;
                selectFeatureInfo.selectFeatureID = selids[0];
                selectFeatureInfoList.add(selectFeatureInfo);
            }
        }

        //根据待选图层确定是否弹窗选择
        if(selectFeatureInfoList.size()>1){
            //当前选中要素大于1个图层
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setTitle("请确认选择哪个图层要素?");
            //指定下拉列表的显示数据
            final String[] layerNamelist = getSelectFeatureInfoListName(selectFeatureInfoList);
            //设置一个下拉的列表选择项
            builder.setItems(layerNamelist, new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    Toast.makeText(MainActivity.this, "选择的图层为:" + layerNamelist[which], Toast.LENGTH_SHORT).show();
                    SelectFeatureInfo selectFeaInfo = getFeatureLayerbyName(selectFeatureInfoList,layerNamelist[which]);
                    setSelectFeature(selectFeaInfo);//根据选中图层信息选中当前要素
                }
            });
            builder.show();
        }else if(selectFeatureInfoList.size()==1) {
            SelectFeatureInfo selectFeaInfo = selectFeatureInfoList.get(0);
            setSelectFeature(selectFeaInfo);//根据选中图层信息选中当前要素
        }

    }

    /**
     * 设置选中图层的要素选中信息
     * @param selectFeaInfo 待选图层信息
     */
    private void setSelectFeature(SelectFeatureInfo selectFeaInfo) {
        clearFeatureSelection();//设置选中状态前,清空已选择要素
        selectFeaInfo.featureLayer.selectFeature(selectFeaInfo.selectFeatureID);
        selectFeatureLayer = selectFeaInfo.featureLayer;
        selectFeature = selectFeatureLayer.getFeature(selectFeaInfo.selectFeatureID);
        switch (selectFeature.getGeometry().getType()){
            case POINT:
            case MULTIPOINT:
                selectGraphic = new Graphic(selectFeature.getGeometry(), DrawSymbol.markerSymbol, null);
                break;
            case LINE:
            case POLYLINE:
                selectGraphic = new Graphic(selectFeature.getGeometry(), DrawSymbol.mLineSymbol,null);
                break;
            case ENVELOPE:
            case POLYGON:
                selectGraphic = new Graphic(selectFeature.getGeometry(), DrawSymbol.mFillSymbol, null);
                break;
            default:
                break;
        }
    }

    /**
     * 通过图层名称获取要素
     * @param name 图层名称
     * @return 选中图层信息
     */
    private SelectFeatureInfo getFeatureLayerbyName(List<SelectFeatureInfo> selectFeatureInfoList,String name){
        SelectFeatureInfo selectinfo= null;
        for (int i=0;i<selectFeatureInfoList.size();i++){
            FeatureLayer tmplayer = selectFeatureInfoList.get(i).featureLayer;
           if (tmplayer.getName().equals(name)){
               selectinfo = selectFeatureInfoList.get(i);//选中图层信息
           }
        }
        return selectinfo;
    }

    /**
     * 获取待选择要素列表名称
     * @param selectFeatureInfoList 待选中要素列表信息
     * @return
     */
    private String[] getSelectFeatureInfoListName(List<SelectFeatureInfo> selectFeatureInfoList) {
        List<String> lsname = new ArrayList<>();
        for (int i=0;i<selectFeatureInfoList.size();i++){
            lsname.add(selectFeatureInfoList.get(i).featureLayer.getName());
        }
        return lsname.toArray(new String[lsname.size()]);
    }

    /**
     * 记录当前选中要素信息
     */
    public class SelectFeatureInfo{
        public FeatureLayer featureLayer ;//当前选中要素
        public long selectFeatureID ;//当前选中要素ID
    }
} 
复制代码

3、完整代码

完整代码不定期更新,具体请查阅DEMOt源代码,托管地址:http://git.oschina.net/gis-luq/RuntimeOfflineEdit

 4、运行后编辑结果(以备同步测试使用)

转载请注明出处:http://www.cnblogs.com/gis-luq/p/5858055.html 

相关内容列表

《ArcGIS Runtime SDK for Android开发笔记》——离在线一体化技术:概述

《ArcGIS Runtime SDK for Android开发笔记》——离在线一体化技术:离线矢量数据下载

《ArcGIS Runtime SDK for Android开发笔记》——离在线一体化技术:离线矢量数据编辑

《ArcGIS Runtime SDK for Android开发笔记》——离在线一体化技术:离线矢量数据同步

《ArcGIS Runtime SDK for Android开发笔记》——数据制作篇:发布具有同步能力的FeatureService服务

文章若无特殊说明均为原创,原创作品,允许转载,转载时请务必以超链接形式标明文章出处、作者信息和本声明。
博客:http://www.cnblogs.com/gis-luq​ 作者:gis-luq 邮箱:luqiang.gis@foxmail.com
posted @ 2017-02-23 17:20  疯子110  阅读(325)  评论(0编辑  收藏  举报