在ArcGIS中除了显示不同地图,还有一块非常重要,就是这个实例要介绍的绘图,如:绘制点、线、面等图形。
废话少说直入主题,首先我们还是先来了解一下布局文件main.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<!—地图控件 --> <com.esri.android.map.MapView android:id="@+id/map" android:layout_width="fill_parent" android:layout_height="fill_parent"> </com.esri.android.map.MapView>
<LinearLayout android:orientation="horizontal" android:gravity="left" android:layout_width="wrap_content" android:layout_height="wrap_content" > <!—点击此按钮弹出点、线、面的选择列表 --> <Button android:id="@+id/geometrybutton" android:text="Select Geometry" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!—提示信息显示区域--> <TextView android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxLength="25" android:singleLine="false" android:editable="false" android:gravity="center_horizontal"/> <!—清理绘画的图形 --> <Button android:id="@+id/clearbutton" android:text="Clear" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> </RelativeLayout> |
上面的布局显示的效果如下,两个按钮和一个文本框,文本框是隐藏的。
当点击第一按钮时,弹出一个列表,列表中有三个选项点、线、面。点击任意一个即可在地图上绘制多边形。
下面来看一下DrawGraphicElements.java中的代码,先来看看类中的属性:
MapView mapView = null;//地图控件 //切片服务 ArcGISTiledMapServiceLayer tiledMapServiceLayer = null; //绘图时要用到的图层 GraphicsLayer graphicsLayer = null; //扩展MapOnTouchListener类 MyTouchListener myListener = null;
//点击后弹出的列表按钮 Button geometryButton = null; //点击清除graphicsLayer图层中的要素 Button clearButton = null; TextView label = null;
//切片服务的URL字符串 String mapURL = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/PublicSafety/PublicSafetyBasemap/MapServer"; //列表所需的数据源 final String[] geometryTypes = new String[] { "Point", "Polyline", "Polygon" }; //设置当前选择的哪一项 int selectedGeometryIndex = -1; |
上面的代码设置了后面所需的属性,属性值在onCreate()中初始化
下面来看一下在onCreate中还做了上面事情:
@SuppressWarnings("serial") public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
mapView = (MapView)findViewById(R.id.map); myListener = new MyTouchListener(DrawGraphicElements.this, mapView); //给mapView添加了触摸事件监听 mapView.setOnTouchListener(myListener); geometryButton = (Button) findViewById(R.id.geometrybutton); geometryButton.setEnabled(false); //给按钮添加了一个点击事件监听 geometryButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { showDialog(0); } });
label = (TextView) findViewById(R.id.label);
clearButton = (Button) findViewById(R.id.clearbutton); //设置按钮不可用 clearButton.setEnabled(false);
//给按钮添加了一个点击事件监听 clearButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { graphicsLayer.removeAll();
clearButton.setEnabled(false); } }); tiledMapServiceLayer = new ArcGISTiledMapServiceLayer(mapURL); graphicsLayer = new GraphicsLayer(); //添加地图服务状态改变事件监听 tiledMapServiceLayer .setOnStatusChangedListener(new OnStatusChangedListener() {
public void onStatusChanged(Object arg0, STATUS status) {
if (status .equals(OnStatusChangedListener.STATUS.INITIALIZED)) { geometryButton.setEnabled(true); } } }); //将切片服务与graphicsLayer图层添加到mapView中去 mapView.addLayer(tiledMapServiceLayer); mapView.addLayer(graphicsLayer); } |
从上面的代码和注释可以很清楚的看出,在这段代码中主要干了两件事:一个是初始化属性;另一个是为属性添加添加相应的事件监听。
基础工作做完后,进入重点,也就是我们实现的MyTouchListener类,它继承MapOnTouchListener类,在我们自己实现的类中主要完成了绘图的核心代码,是不是很激动,让我们来看一下吧:
class MyTouchListener extends MapOnTouchListener { //此变量是用来保存线或者面的轨迹数据的 MultiPath poly; //判断是执行的哪种绘图方式,它可以为这三种值:point,polgyline,polgyon String type = ""; //绘画点时用于储存点的变量 Point startPoint = null; //构造方法 public MyTouchListener(Context context, MapView view) { super(context, view); } // public void setType(String geometryType) { this.type = geometryType; }
public String getType() { return this.type; }
//当我们绘制点时执行的处理函数 public boolean onSingleTap(MotionEvent e) { if (type.length() > 1 && type.equalsIgnoreCase("POINT")) { graphicsLayer.removeAll();//绘制点时首先清除图层要素 //生成点图形,并设置相应的样式 Graphic graphic = new Graphic(mapView.toMapPoint(new Point(e.getX(), e .getY())),new SimpleMarkerSymbol(Color.RED,25,STYLE.CIRCLE)); //将点要素添加到图层上 graphicsLayer.addGraphic(graphic); //设置按钮可用 clearButton.setEnabled(true); return true; } return false;
} //当绘制线或者面时调用的函数 public boolean onDragPointerMove(MotionEvent from, MotionEvent to) { if (type.length() > 1 && (type.equalsIgnoreCase("POLYLINE") || type .equalsIgnoreCase("POLYGON"))) { //得到移动后的点 Point mapPt = mapView.toMapPoint(to.getX(), to.getY());
//判断startPoint是否为空,如果为空,给startPoint赋值 if (startPoint == null) { graphicsLayer.removeAll(); poly = type.equalsIgnoreCase("POLYLINE") ?new Polyline() : new Polygon(); startPoint = mapView.toMapPoint(from.getX(), from.getY()); //将第一个点存入poly中 poly.startPath((float) startPoint.getX(), (float) startPoint.getY());
Graphic graphic = new Graphic(startPoint,new SimpleLineSymbol(Color.RED,5));
graphicsLayer.addGraphic(graphic); } //将移动的点放入poly中 poly.lineTo((float) mapPt.getX(), (float) mapPt.getY());
return true; } return super.onDragPointerMove(from, to);
} //当绘制完线或面,离开屏幕时调用的函数 @Override public boolean onDragPointerUp(MotionEvent from, MotionEvent to) { if (type.length() > 1 && (type.equalsIgnoreCase("POLYLINE") || type .equalsIgnoreCase("POLYGON"))) { //判断当绘制的是面时,将起始点填入到poly中形成闭合 if (type.equalsIgnoreCase("POLYGON")) { poly.lineTo((float) startPoint.getX(), (float) startPoint.getY()); graphicsLayer.removeAll(); graphicsLayer.addGraphic(new Graphic(poly,new SimpleFillSymbol(Color.RED)));
} //最后将poly图形添加到图层中去 graphicsLayer.addGraphic(new Graphic(poly,new SimpleLineSymbol(Color.BLUE,5))); startPoint = null; clearButton.setEnabled(true); return true; } return super.onDragPointerUp(from, to); } } |
通过上面的代码和注释我们可以知道,在这个类中主要完成了一下几项工作:
1、当点击地图时,将点添加到图层上并且将其渲染;
2、当在屏幕上滑动时,将滑动生成的点逐步添加到poly变量中;
3、当滑动完离开屏幕时,判断是绘制的线还是面,当是面时,将第一个点追加到poly变量中,并将poly变量添加到图层中去。
所有绘图的操作基本都在上面的代码中实现,还剩下一小部分代码为点击geometryButton按钮而弹出的列表,下面的形式如果对于Android开发经验的一定不会陌生,对了,就是弹出列表的一种方式,而当我们选择不同的选项时调用myListener.setType()来指定绘图方式。
protected Dialog onCreateDialog(int id) { return new AlertDialog.Builder(DrawGraphicElements.this) .setTitle("Select Geometry") // geometryTypes为这个弹出框的数据源 .setItems(geometryTypes, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog,int which) { graphicsLayer.removeAll();
// ignore first element Toast toast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_LONG); toast.setGravity(Gravity.BOTTOM, 0, 0);//提示信息
// Get item selected by user. String geomType = geometryTypes[which]; label.setText(geomType + " selected."); selectedGeometryIndex = which;
// process user selection if (geomType.equalsIgnoreCase("Polygon")) { myListener.setType("POLYGON"); toast.setText("Drag finger across screen to draw a Polygon. \nRelease finger to stop drawing."); } else if (geomType.equalsIgnoreCase("Polyline")) { myListener.setType("POLYLINE"); toast.setText("Drag finger across screen to draw a Polyline. \nRelease finger to stop drawing."); } else if (geomType.equalsIgnoreCase("Point")) { myListener.setType("POINT"); toast.setText("Tap on screen once to draw a Point."); }
toast.show(); } }).create(); } |
到此,绘图的实例的解析已经完成,是不是也那么难,只要熟练掌握MapOnTouchListener类和MultiPath类,绘图功能竟在掌控中。
注:由于后面的代码越来越长,下面的示例只挑选一下复杂的代码来解释,像上面的变量初始化代码将不再列出,学习时请根据示例来对应相应代码。