Android开发笔记(一百零三)地图与定位SDK

集成地图SDK

国内常用的地图SDK就是百度和高德了,二者的用法大同小异,可按照官网上的开发指南一步步来。下面是我在集成地图SDK时遇到的问题说明:

1、点击基本地图功能选项,不能打开地图,弹出“key验证出错!请在AndroidManifest.xml文件中检查key设置的”的红色字提示。查看日志提示“galaxy lib host missing meta-data,make sure you know the right way to integrate galaxy”

该问题是因为key值对应的签名与app打包用的签名不一致。app在开发时与发布时有两个不同的签名,开发时用的是ADT默认签名,查看默认签名的SHA1值可依次选择“Window”->“Preferences”->“Android”->“Build  SHA1 fingerprint”。app发布时的签名是密钥文件的签名,查看发布签名的SHA1值可依次选择“File”->“Export”->“Export Android Application”->“Next”后选择密钥文件并输入密码与app输出路径->在“Certificate
fingerprints”下查看SHA1值。

2、百度地图SDK3.6及以上版本找不到overlayutil包。

这是因为新版SDK的jar包不再包含这部分源码,得到官方demo的src目录下获取源码加入到开发者自己的工程中,源码路径为:BaiduMap_AndroidMapSDK_v3.7.1_Sample\BaiduMapsApiDemo\src\com\baidu\mapapi

3、在一个工程中同时包含了百度地图和高德地图的sdk,编译时报错“Found duplicate file for APK: assets/lineDashTexture.png”。

这是因为百度和高德的sdk,其jar包存在同名文件“assets/lineDashTexture.png”,所以无法通过编译。即百度sdk与高德sdk是互斥的,不能同时存在于同个工程中,必须分开来使用。

显示地图和定位

对于一个地图SDK来说,首先要显示地图,然后定位到当前城市。

这方面百度地图和高德地图的处理代码差不多,下面是两种地图sdk显示并定位的代码例子:

百度地图

	// 以下主要是定位用到的代码
	private MapView mMapView;
	private BaiduMap mMapLayer;
	private LocationClient mLocClient;
	private boolean isFirstLoc = true;// 是否首次定位

	private void initLocation() {
		mMapView = (MapView) findViewById(R.id.bmapView);
		// 先隐藏地图,待定位到当前城市时再显示
		mMapView.setVisibility(View.INVISIBLE);
		mMapLayer = mMapView.getMap();
		mMapLayer.setOnMapClickListener(this);
		// 开启定位图层
		mMapLayer.setMyLocationEnabled(true);
		mLocClient = new LocationClient(this);
		// 设置定位监听器
		mLocClient.registerLocationListener(new MyLocationListenner());
		LocationClientOption option = new LocationClientOption();
		option.setOpenGps(true);// 打开gps
		option.setCoorType("bd09ll"); // 设置坐标类型
		option.setScanSpan(1000);
		option.setIsNeedAddress(true); // 设置true才能获得详细的地址信息
		// 设置定位参数
		mLocClient.setLocOption(option);
		// 开始定位
		mLocClient.start();
		 //获取最近一次的位置
		// mLocClient.getLastKnownLocation();
	}

	public class MyLocationListenner implements BDLocationListener {

		@Override
		public void onReceiveLocation(BDLocation location) {
			// map view 销毁后不在处理新接收的位置
			if (location == null || mMapView == null) {
				Log.d(TAG, "location is null or mMapView is null");
				return;
			}
			m_latitude = location.getLatitude();
			m_longitude = location.getLongitude();
			String position = String.format("当前位置:%s|%s|%s|%s|%s|%s|%s",
					location.getProvince(), location.getCity(),
					location.getDistrict(), location.getStreet(),
					location.getStreetNumber(), location.getAddrStr(),
					location.getTime());
			loc_position.setText(position);
			MyLocationData locData = new MyLocationData.Builder()
					.accuracy(location.getRadius())
					// 此处设置开发者获取到的方向信息,顺时针0-360
					.direction(100).latitude(m_latitude)
					.longitude(m_longitude).build();
			mMapLayer.setMyLocationData(locData);
			if (isFirstLoc) {
				isFirstLoc = false;
				LatLng ll = new LatLng(m_latitude, m_longitude);
				MapStatusUpdate update = MapStatusUpdateFactory.newLatLngZoom(ll, 14);
				mMapLayer.animateMapStatus(update);
				// 定位到当前城市时再显示图层
				mMapView.setVisibility(View.VISIBLE);
			}
		}

		public void onReceivePoi(BDLocation poiLocation) {
		}
	}

高德地图

	// 以下主要是定位用到的代码
	private MapView mMapView;
	private AMap mMapLayer;
	private AMapLocationClient mLocClient;
	private boolean isFirstLoc = true;// 是否首次定位

	private void initLocation(Bundle savedInstanceState) {
		mMapView = (MapView) findViewById(R.id.amapView);
		mMapView.onCreate(savedInstanceState);
		// 先隐藏地图,待定位到当前城市时再显示
		mMapView.setVisibility(View.INVISIBLE);
		if (mMapLayer == null) {
			mMapLayer = mMapView.getMap();
		}
		mMapLayer.setOnMapClickListener(this);
		// 开启定位图层
		mMapLayer.setMyLocationEnabled(true);
		mMapLayer.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);
		mLocClient = new AMapLocationClient(this.getApplicationContext());
		// 设置定位监听器
		mLocClient.setLocationListener(new MyLocationListenner());
		AMapLocationClientOption option = new AMapLocationClientOption();
		option.setLocationMode(AMapLocationMode.Battery_Saving);
		option.setNeedAddress(true); // 设置true才能获得详细的地址信息
		// 设置定位参数
		mLocClient.setLocationOption(option);
		// 开始定位
		mLocClient.startLocation();
		 //获取最近一次的位置
		// mLocClient.getLastKnownLocation();
	}

	public class MyLocationListenner implements AMapLocationListener {

		@Override
		public void onLocationChanged(AMapLocation location) {
			// map view 销毁后不在处理新接收的位置
			if (location == null || mMapView == null) {
				Log.d(TAG, "location is null or mMapView is null");
				return;
			}
			m_latitude = location.getLatitude();
			m_longitude = location.getLongitude();
			String position = String.format("当前位置:%s|%s|%s|%s|%s|%s|%s",
					location.getProvince(), location.getCity(),
					location.getDistrict(), location.getStreet(),
					location.getAdCode(), location.getAddress(),
					location.getTime());
			loc_position.setText(position);
			if (isFirstLoc) {
				isFirstLoc = false;
				LatLng ll = new LatLng(m_latitude, m_longitude);
                CameraUpdate update = CameraUpdateFactory.newLatLngZoom(ll, 12);
				mMapLayer.moveCamera(update);
				// 定位到当前城市时再显示图层
				mMapView.setVisibility(View.VISIBLE);
			}
		}
	}

POI搜索

POI即地图注点,它是“Point of Interest”的缩写,在地图上标注地点名称、类别、经度、纬度等信息,是一个带位置信息的地图标注。POI搜索是地图sdk的一个重要应用,根据关键字搜索并在地图上显示POI结果,这是智能出行的基础。

下面是使用百度地图搜索POI的截图:

下面是两种地图sdk进行POI搜索的代码例子:

百度地图

	// 以下主要是POI搜索用到的代码
	private PoiSearch mPoiSearch = null;
	private SuggestionSearch mSuggestionSearch = null;
	private AutoCompleteTextView mKey = null;
	private EditText mScope = null;
	private Button btn_search, btn_nextpage, btn_cleardata;
	private ArrayAdapter<String> sugAdapter = null;
	private int load_Index = 0;

	private void initMap() {
		mPoiSearch = PoiSearch.newInstance();
		mPoiSearch.setOnGetPoiSearchResultListener(this);
		mSuggestionSearch = SuggestionSearch.newInstance();
		mSuggestionSearch.setOnGetSuggestionResultListener(this);
		mScope = (EditText) findViewById(R.id.poi_city);
		mKey = (AutoCompleteTextView) findViewById(R.id.poi_searchkey);
		btn_search = (Button) findViewById(R.id.search);
		btn_nextpage = (Button) findViewById(R.id.map_next_data);
		btn_cleardata = (Button) findViewById(R.id.map_clear_data);
		btn_search.setOnClickListener(this);
		btn_nextpage.setOnClickListener(this);
		btn_cleardata.setOnClickListener(this);
		sugAdapter = new ArrayAdapter<String>(this, R.layout.spinner_dropdown_item);
		mKey.setAdapter(sugAdapter);

		// 当输入关键字变化时,动态更新建议列表
		mKey.addTextChangedListener(new TextWatcher() {

			@Override
			public void afterTextChanged(Editable arg0) {
			}

			@Override
			public void beforeTextChanged(CharSequence arg0, int arg1,
					int arg2, int arg3) {
			}

			@Override
			public void onTextChanged(CharSequence cs, int arg1, int arg2,
					int arg3) {
				if (cs.length() <= 0) {
					return;
				}
				String city = mScope.getText().toString();
				// 使用建议搜索服务获取建议列表,结果在onGetSuggestionResult中更新
				mSuggestionSearch
						.requestSuggestion((new SuggestionSearchOption())
								.keyword(cs.toString()).city(city));
			}
		});
	}

	@Override
	public void onGetSuggestionResult(SuggestionResult res) {
		if (res == null || res.getAllSuggestions() == null) {
			return;
		} else {
			sugAdapter.clear();
			for (SuggestionResult.SuggestionInfo info : res.getAllSuggestions()) {
				if (info.key != null) {
					sugAdapter.add(info.key);
				}
			}
			sugAdapter.notifyDataSetChanged();
		}
	}

	// 影响搜索按钮点击事件
	public void searchButtonProcess(View v) {
		Log.d(TAG, "editCity=" + mScope.getText().toString()
				+ ", editSearchKey=" + mKey.getText().toString()
				+ ", load_Index=" + load_Index);
		String keyword = mKey.getText().toString();
		if (search_method == SEARCH_CITY) {
			String city = mScope.getText().toString();
			mPoiSearch.searchInCity((new PoiCitySearchOption()).city(city)
					.keyword(keyword).pageNum(load_Index));
		} else if (search_method == SEARCH_NEARBY) {
			LatLng position = new LatLng(m_latitude, m_longitude);
			int radius = Integer.parseInt(mScope.getText().toString());
			mPoiSearch.searchNearby((new PoiNearbySearchOption())
					.location(position).keyword(keyword).radius(radius)
					.pageNum(load_Index));
		}
	}

	public void goToNextPage(View v) {
		load_Index++;
		searchButtonProcess(null);
	}

	public void onGetPoiResult(PoiResult result) {
		if (result == null
				|| result.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {
			Toast.makeText(this, "未找到结果", Toast.LENGTH_LONG).show();
			return;
		} else if (result.error == SearchResult.ERRORNO.NO_ERROR) {
			mMapLayer.clear();
			PoiOverlay overlay = new MyPoiOverlay(mMapLayer);
			mMapLayer.setOnMarkerClickListener(overlay);
			List<PoiInfo> poiList = result.getAllPoi();
			overlay.setData(result);
			overlay.addToMap();
			overlay.zoomToSpan();
//			for (PoiInfo poi : poiList) {
//			String detail = String.format(
//					"uid=%s,city=%s,name=%s,phone=%s, address=%s", poi.uid,
//					poi.city, poi.name, poi.phoneNum, poi.address);
//			Log.d(TAG, detail); // 坐标为poi.location(LatLng结构)
//			}
		} else if (result.error == SearchResult.ERRORNO.AMBIGUOUS_KEYWORD) {
			// 当输入关键字在本市没有找到,但在其他城市找到时,返回包含该关键字信息的城市列表
			String strInfo = "在";
			for (CityInfo cityInfo : result.getSuggestCityList()) {
				strInfo += cityInfo.city + ",";
			}
			strInfo += "找到结果";
			Toast.makeText(this, strInfo, Toast.LENGTH_LONG).show();
		}
	}

	public void onGetPoiDetailResult(PoiDetailResult result) {
		if (result.error != SearchResult.ERRORNO.NO_ERROR) {
			Toast.makeText(this, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
		} else {
			Log.d(TAG,
					"name=" + result.getName() + ",address="
							+ result.getAddress() + ",detail_url="
							+ result.getDetailUrl() + ",shop_hours="
							+ result.getShopHours() + ",telephone="
							+ result.getTelephone() + ",price="
							+ result.getPrice() + ",type=" + result.getType()
							+ ",tag=" + result.getTag());
			Toast.makeText(this, result.getName() + ": " + result.getAddress(),
					Toast.LENGTH_SHORT).show();
		}
	}

	private class MyPoiOverlay extends PoiOverlay {

		public MyPoiOverlay(BaiduMap baiduMap) {
			super(baiduMap);
		}

		@Override
		public boolean onPoiClick(int index) {
			super.onPoiClick(index);
			PoiInfo poi = getPoiResult().getAllPoi().get(index);
			mPoiSearch.searchPoiDetail((new PoiDetailSearchOption()).poiUid(poi.uid));
			return true;
		}
	}

高德地图

	// 以下主要是POI搜索用到的代码
	private PoiSearch mPoiSearch = null;
	private AutoCompleteTextView mKey = null;
	private EditText mScope = null;
	private Button btn_search, btn_nextpage, btn_cleardata;
	private ArrayAdapter<String> sugAdapter = null;
	private int load_Index = 0;

	private void initMap() {
		mScope = (EditText) findViewById(R.id.poi_city);
		mKey = (AutoCompleteTextView) findViewById(R.id.poi_searchkey);
		btn_search = (Button) findViewById(R.id.search);
		btn_nextpage = (Button) findViewById(R.id.map_next_data);
		btn_cleardata = (Button) findViewById(R.id.map_clear_data);
		btn_search.setOnClickListener(this);
		btn_nextpage.setOnClickListener(this);
		btn_cleardata.setOnClickListener(this);
		sugAdapter = new ArrayAdapter<String>(this, R.layout.spinner_dropdown_item);
		mKey.setAdapter(sugAdapter);

		// 当输入关键字变化时,动态更新建议列表
		mKey.addTextChangedListener(new TextWatcher() {

			@Override
			public void afterTextChanged(Editable arg0) {
			}

			@Override
			public void beforeTextChanged(CharSequence arg0, int arg1,
					int arg2, int arg3) {
			}

			@Override
			public void onTextChanged(CharSequence cs, int arg1, int arg2,
					int arg3) {
				if (cs.length() <= 0) {
					return;
				}
				String city = mScope.getText().toString();
				// 使用建议搜索服务获取建议列表,结果在onGetInputtips中更新
			    InputtipsQuery inputquery = new InputtipsQuery(cs.toString(), city);
			    Inputtips inputTips = new Inputtips(GaodeActivity.this, inputquery);
			    inputTips.setInputtipsListener(GaodeActivity.this);
			    inputTips.requestInputtipsAsyn();
			}
		});
	}

	@Override
	public void onGetInputtips(List<Tip> tipList, int rCode) {
		if (rCode != 1000) {
			Toast.makeText(this, "推荐文字错误代码是"+rCode, Toast.LENGTH_LONG).show();
		} else {
			sugAdapter.clear();
			for (Tip info : tipList) {
				if (info.getName() != null) {
					sugAdapter.add(info.getName());
				}
			}
			sugAdapter.notifyDataSetChanged();
		}
	}

	// 影响搜索按钮点击事件
	public void searchButtonProcess(View v) {
		Log.d(TAG, "editCity=" + mScope.getText().toString()
				+ ", editSearchKey=" + mKey.getText().toString()
				+ ", load_Index=" + load_Index);
		String keyword = mKey.getText().toString();
		if (search_method == SEARCH_CITY) {
			String city = mScope.getText().toString();
			PoiSearch.Query query = new PoiSearch.Query(keyword, null, city);
			query.setPageSize(10);
			query.setPageNum(load_Index);
			mPoiSearch = new PoiSearch(this, query);
			mPoiSearch.setOnPoiSearchListener(this);
			mPoiSearch.searchPOIAsyn();
		} else if (search_method == SEARCH_NEARBY) {
			LatLonPoint position = new LatLonPoint(m_latitude, m_longitude);
			int radius = Integer.parseInt(mScope.getText().toString());
			PoiSearch.Query query = new PoiSearch.Query(keyword, null, "福州");
			query.setPageSize(10);
			query.setPageNum(load_Index);
			mPoiSearch = new PoiSearch(this, query);
			SearchBound bound = new SearchBound(position, radius);
			mPoiSearch.setBound(bound);
			mPoiSearch.setOnPoiSearchListener(this);
			mPoiSearch.searchPOIAsyn();
		}
	}

	public void goToNextPage(View v) {
		load_Index++;
		searchButtonProcess(null);
	}

	@Override
	public void onPoiSearched(PoiResult result, int rCode) {
		if (rCode != 1000) {
			Toast.makeText(this, "POI错误代码是"+rCode, Toast.LENGTH_LONG).show();
		} else if (result == null || result.getQuery() == null) {
			Toast.makeText(this, "未找到结果", Toast.LENGTH_LONG).show();
			return;
		} else {
			mMapLayer.clear();
			List<PoiItem> poiList = result.getPois();
			// 当搜索不到poiitem数据时,会返回含有搜索关键字的城市信息
			List<SuggestionCity> suggestionCities = result.getSearchSuggestionCitys();
			if (poiList!=null && poiList.size()>0) {
				PoiOverlay poiOverlay = new PoiOverlay(mMapLayer, poiList);
				//从地图上移除原POI信息
				poiOverlay.removeFromMap();
				//往地图添加新POI信息
				poiOverlay.addToMap();
				poiOverlay.zoomToSpan();
				//给POI添加监听器。在点击POI时提示POI信息
				mMapLayer.setOnMarkerClickListener(new OnMarkerClickListener() {
					@Override
					public boolean onMarkerClick(Marker marker) {
						marker.showInfoWindow();
						return true;
					}
				});
//				for (PoiItem poi : poiList) {
//					String detail = String.format(
//							"uid=%s,city=%s,name=%s,phone=%s, address=%s", poi.getPoiId(),
//							poi.getCityName(), poi.getTitle(), poi.getTel(), poi.getAdName());
//					Log.d(TAG, detail); // 坐标为poi.location(LatLng结构)
//				}
			} else if (suggestionCities != null && suggestionCities.size() > 0) {
				String infomation = "推荐城市\n";
				for (int i = 0; i < suggestionCities.size(); i++) {
					SuggestionCity city = suggestionCities.get(i);
					infomation += "城市名称:" + city.getCityName() + "城市区号:"
							+ city.getCityCode() + "城市编码:"
							+ city.getAdCode() + "\n";
				}
				Toast.makeText(this, infomation, Toast.LENGTH_LONG).show();
			} else {
				Toast.makeText(this, "结果记录数为0", Toast.LENGTH_LONG).show();
			}
			return;
		}
	}

	@Override
	public void onPoiItemSearched(PoiItem paramPoiItem, int paramInt) {
		// TODO Auto-generated method stub

	}

测距、测面积

测量距离和测量面积是地图sdk的又一个应用,除了在地图上添加标注之外,就是要用到数学的两个公式。

其中测距用的是勾股定理(又名商高定理):勾股定理是一个基本的几何定理:一个直角三角形,两直角边的平方和等于斜边的平方。如果直角三角形两直角边为a和b,斜边为c,那么a*a+b*b=c*c

测面积用的是海伦公式(又名秦九韶公式):海伦公式是利用三角形的三个边长直接求三角形面积的公式,表达式为:S=√p(p-a)(p-b)(p-c)。基于海伦公式,可以推导出根据多边形各边长求多边形面积的公式,即S = 0.5 * ( (x0*y1-x1*y0) + (x1*y2-x2*y1) + ... + (xn*y0-x0*yn) )

两种地图sdk在测量上的数学原理是一样的,只在添加地图标注上有些小差异,下面是使用高德地图进行测量的截图:

下面是两种地图sdk进行测量的代码例子:

百度地图

	// 下面是在地图上添加绘图操作
	private static int lineColor = 0x55FF0000;
	private static int arcColor = 0xbb00FFFF;
	private static int textColor = 0x990000FF;
	private static int polygonColor = 0x77FFFF00;
	private static int radius = 100;
	private ArrayList<LatLng> posArray = new ArrayList<LatLng>();
	boolean is_polygon = false;

	private void addDot(LatLng pos) {
		if (is_polygon == true && posArray.size() > 1
				&& MapUtil.isInsidePolygon(pos, posArray) == true) {
			Log.d(TAG, "isInsidePolygon");
			LatLng centerPos = MapUtil.getCenterPos(posArray);
			OverlayOptions ooText = new TextOptions().bgColor(0x00ffffff)
					.fontSize(26).fontColor(textColor).text("标题")// .rotate(-30)
					.position(centerPos);
			mMapLayer.addOverlay(ooText);
			return;
		}
		if (is_polygon == true) {
			Log.d(TAG, "is_polygon == true");
			posArray.clear();
			is_polygon = false;
		}
		boolean is_first = false;
		LatLng thisPos = pos;
		if (posArray.size() > 0) {
			LatLng firstPos = posArray.get(0);
			int distance = (int) Math.round(MapUtil.getShortDistance(
					thisPos.longitude, thisPos.latitude, firstPos.longitude,
					firstPos.latitude));
			//多次点击起点,要忽略之
			if (posArray.size()==1 && distance<=0) {
				return;
			} else if (posArray.size() > 1) {
				LatLng lastPos = posArray.get(posArray.size()-1);
				int lastDistance = (int) Math.round(MapUtil.getShortDistance(
						thisPos.longitude, thisPos.latitude, lastPos.longitude,
						lastPos.latitude));
				//重复响应当前位置的点击,要忽略之
				if (lastDistance <= 0) {
					return;
				}
			}
			if (distance < radius * 2) {
				thisPos = firstPos;
				is_first = true;
			}
			Log.d(TAG, "distance="+distance+", radius="+radius+", is_first="+is_first);

			// 画直线
			LatLng lastPos = posArray.get(posArray.size() - 1);
			List<LatLng> points = new ArrayList<LatLng>();
			points.add(lastPos);
			points.add(thisPos);
			OverlayOptions ooPolyline = new PolylineOptions().width(2)
					.color(lineColor).points(points);
			mMapLayer.addOverlay(ooPolyline);

			// 下面计算两点之间距离
			distance = (int) Math.round(MapUtil.getShortDistance(
					thisPos.longitude, thisPos.latitude, lastPos.longitude,
					lastPos.latitude));
			String disText = "";
			if (distance > 1000) {
				disText = Math.round(distance * 10 / 1000) / 10d + "公里";
			} else {
				disText = distance + "米";
			}
			LatLng llText = new LatLng(
					(thisPos.latitude + lastPos.latitude) / 2,
					(thisPos.longitude + lastPos.longitude) / 2);
			OverlayOptions ooText = new TextOptions().bgColor(0x00ffffff)
					.fontSize(24).fontColor(textColor).text(disText)// .rotate(-30)
					.position(llText);
			mMapLayer.addOverlay(ooText);
		}
		if (is_first != true) {
			// 画圆圈
			OverlayOptions ooCircle = new CircleOptions().fillColor(lineColor)
					.center(thisPos).stroke(new Stroke(2, 0xAAFF0000)).radius(radius);
			mMapLayer.addOverlay(ooCircle);
			// 画图片标记
			BitmapDescriptor bitmapDesc = BitmapDescriptorFactory
					.fromResource(R.drawable.icon_geo);
			OverlayOptions ooMarker = new MarkerOptions().draggable(false)
					.visible(true).icon(bitmapDesc).position(thisPos);
			mMapLayer.addOverlay(ooMarker);
			mMapLayer.setOnMarkerClickListener(new OnMarkerClickListener() {
				@Override
				public boolean onMarkerClick(Marker marker) {
					LatLng markPos = marker.getPosition();
					addDot(markPos);
					return true;
				}
			});
		} else {
			Log.d(TAG, "posArray.size()="+posArray.size());
			//可能存在地图与标记同时响应点击事件的情况
			if (posArray.size() < 3) {
				posArray.clear();
				is_polygon = false;
				return;
			}
			// 画多边形
			OverlayOptions ooPolygon = new PolygonOptions().points(posArray)
					.stroke(new Stroke(1, 0xFF00FF00))
					.fillColor(polygonColor);
			mMapLayer.addOverlay(ooPolygon);
			is_polygon = true;

			// 下面计算多边形的面积
			LatLng centerPos = MapUtil.getCenterPos(posArray);
			double area = Math.round(MapUtil.getArea(posArray));
			String areaText = "";
			if (area > 1000000) {
				areaText = Math.round(area * 100 / 1000000) / 100d + "平方公里";
			} else {
				areaText = (int) area + "平方米";
			}
			OverlayOptions ooText = new TextOptions().bgColor(0x00ffffff)
					.fontSize(26).fontColor(textColor).text(areaText)// .rotate(-30)
					.position(centerPos);
			mMapLayer.addOverlay(ooText);
		}
		posArray.add(thisPos);
		if (posArray.size() >= 3) {
			// 画弧线
			OverlayOptions ooArc = new ArcOptions()
					.color(arcColor)
					.width(2)
					.points(posArray.get(posArray.size() - 1),
							posArray.get(posArray.size() - 2),
							posArray.get(posArray.size() - 3));
			mMapLayer.addOverlay(ooArc);
		}
	}

	@Override
	public void onMapClick(LatLng arg0) {
		addDot(arg0);
	}

	@Override
	public boolean onMapPoiClick(MapPoi arg0) {
		addDot(arg0.getPosition());
		return false;
	}

高德地图

	// 下面是在地图上添加绘图操作
	private static int lineColor = 0x55FF0000;
	private static int arcColor = 0xbb00FFFF;
	private static int textColor = 0x990000FF;
	private static int polygonColor = 0x77FFFF00;
	private static int radius = 100;
	private ArrayList<LatLng> posArray = new ArrayList<LatLng>();
	boolean is_polygon = false;

	private void addDot(LatLng pos) {
		if (is_polygon == true && posArray.size() > 1
				&& MapUtil.isInsidePolygon(pos, posArray) == true) {
			Log.d(TAG, "isInsidePolygon");
			LatLng centerPos = MapUtil.getCenterPos(posArray);
			TextOptions ooText = new TextOptions().backgroundColor(0x00ffffff)
					.fontSize(26).fontColor(textColor).text("标题")// .rotate(-30)
					.position(centerPos);
			mMapLayer.addText(ooText);
			return;
		}
		if (is_polygon == true) {
			Log.d(TAG, "is_polygon == true");
			posArray.clear();
			is_polygon = false;
		}
		boolean is_first = false;
		LatLng thisPos = pos;
		if (posArray.size() > 0) {
			LatLng firstPos = posArray.get(0);
			int distance = (int) Math.round(MapUtil.getShortDistance(
					thisPos.longitude, thisPos.latitude, firstPos.longitude,
					firstPos.latitude));
			//多次点击起点,要忽略之
			if (posArray.size()==1 && distance<=0) {
				return;
			} else if (posArray.size() > 1) {
				LatLng lastPos = posArray.get(posArray.size()-1);
				int lastDistance = (int) Math.round(MapUtil.getShortDistance(
						thisPos.longitude, thisPos.latitude, lastPos.longitude,
						lastPos.latitude));
				//重复响应当前位置的点击,要忽略之
				if (lastDistance <= 0) {
					return;
				}
			}
			if (distance < radius * 2) {
				thisPos = firstPos;
				is_first = true;
			}
			Log.d(TAG, "distance="+distance+", radius="+radius+", is_first="+is_first);

			// 画直线
			LatLng lastPos = posArray.get(posArray.size() - 1);
			List<LatLng> points = new ArrayList<LatLng>();
			points.add(lastPos);
			points.add(thisPos);
			PolylineOptions ooPolyline = new PolylineOptions().width(2)
					.color(lineColor).addAll(points);
			mMapLayer.addPolyline(ooPolyline);

			// 下面计算两点之间距离
			distance = (int) Math.round(MapUtil.getShortDistance(
					thisPos.longitude, thisPos.latitude, lastPos.longitude,
					lastPos.latitude));
			String disText = "";
			if (distance > 1000) {
				disText = Math.round(distance * 10 / 1000) / 10d + "公里";
			} else {
				disText = distance + "米";
			}
			LatLng llText = new LatLng(
					(thisPos.latitude + lastPos.latitude) / 2,
					(thisPos.longitude + lastPos.longitude) / 2);
			TextOptions ooText = new TextOptions().backgroundColor(0x00ffffff)
					.fontSize(24).fontColor(textColor).text(disText)// .rotate(-30)
					.position(llText);
			mMapLayer.addText(ooText);
		}
		if (is_first != true) {
			// 画圆圈
			CircleOptions ooCircle = new CircleOptions().fillColor(lineColor)
					.center(thisPos).strokeWidth(2).strokeColor(0xAAFF0000).radius(radius);
			mMapLayer.addCircle(ooCircle);
			// 画图片标记
			BitmapDescriptor bitmapDesc = BitmapDescriptorFactory
					.fromResource(R.drawable.icon_geo);
			MarkerOptions ooMarker = new MarkerOptions().draggable(false)
					.visible(true).icon(bitmapDesc).position(thisPos);
			mMapLayer.addMarker(ooMarker);
			mMapLayer.setOnMarkerClickListener(new OnMarkerClickListener() {
				@Override
				public boolean onMarkerClick(Marker marker) {
					LatLng markPos = marker.getPosition();
					addDot(markPos);
					marker.showInfoWindow();
					return true;
				}
			});
		} else {
			Log.d(TAG, "posArray.size()="+posArray.size());
			//可能存在地图与标记同时响应点击事件的情况
			if (posArray.size() < 3) {
				posArray.clear();
				is_polygon = false;
				return;
			}
			// 画多边形
			PolygonOptions ooPolygon = new PolygonOptions().addAll(posArray)
					.strokeColor(0xFF00FF00).strokeWidth(1)
					.fillColor(polygonColor);
			mMapLayer.addPolygon(ooPolygon);
			is_polygon = true;

			// 下面计算多边形的面积
			LatLng centerPos = MapUtil.getCenterPos(posArray);
			double area = Math.round(MapUtil.getArea(posArray));
			String areaText = "";
			if (area > 1000000) {
				areaText = Math.round(area * 100 / 1000000) / 100d + "平方公里";
			} else {
				areaText = (int) area + "平方米";
			}
			TextOptions ooText = new TextOptions().backgroundColor(0x00ffffff)
					.fontSize(26).fontColor(textColor).text(areaText)// .rotate(-30)
					.position(centerPos);
			mMapLayer.addText(ooText);
		}
		posArray.add(thisPos);
		if (posArray.size() >= 3) {
			// 画弧线
			ArcOptions ooArc = new ArcOptions()
					.strokeColor(arcColor)
					.strokeWidth(2)
					.point(posArray.get(posArray.size() - 1),
							posArray.get(posArray.size() - 2),
							posArray.get(posArray.size() - 3));
			mMapLayer.addArc(ooArc);
		}
	}

	@Override
	public void onMapClick(LatLng arg0) {
		addDot(arg0);
	}

点此查看Android开发笔记的完整目录

时间: 2024-10-13 18:58:14

Android开发笔记(一百零三)地图与定位SDK的相关文章

【转】Android开发笔记(序)写在前面的目录

原文:http://blog.csdn.net/aqi00/article/details/50012511 知识点分类 一方面写写自己走过的弯路掉进去的坑,避免以后再犯:另一方面希望通过分享自己的经验教训,与网友互相切磋,从而去芜存菁进一步提升自己的水平.因此博主就想,入门的东西咱就不写了,人不能老停留在入门上:其次是想拾缺补漏,写写虽然小众却又用得着的东西:另外就是想以实用为主,不求大而全,但求小而精:还有就是有的知识点是java的,只是Android开发也会经常遇上,所以蛮记下来.个人的经

Android开发笔记(一百零六)支付缴费SDK

第三方支付 第三方支付指的是第三方平台与各银行签约,在买方与卖方之间实现中介担保,从而增强了支付交易的安全性.国内常用的支付平台主要是支付宝和微信支付,其中支付宝的市场份额为71.5%,微信支付的市场份额为15.99%,也就是说这两家垄断了八分之七的支付市场(2015年数据).除此之外,还有几个app开发会用到的支付平台,包括:银联支付,主要用于公共事业缴费,如水电煤.有线电视.移动电信等等的充值:易宝支付,主要用于各种报名考试的缴费,特别是公务员与事业单位招考:快钱,被万达收购,主要用于航空旅

Android开发笔记(一百三十四)协调布局CoordinatorLayout

协调布局CoordinatorLayout Android自5.0之后对UI做了较大的提升,一个重大的改进是推出了MaterialDesign库,而该库的基础即为协调布局CoordinatorLayout,几乎所有的design控件都依赖于该布局.协调布局的含义,指的是内部控件互相之前的动作关联,比如在A视图的位置发生变化之时,B视图的位置也按照某种规则来变化,仿佛弹钢琴有了协奏曲一般. 使用CoordinatorLayout时,要注意以下几点:1.导入design库:2.根布局采用androi

Android开发笔记(一百三十二)矢量图形与矢量动画

矢量图形VectorDrawable 与水波图形RippleDrawable一样,矢量图形VectorDrawable也是Android5.0之后新增的图形类.矢量图不同于一般的图形,它是由一系列几何曲线构成的图像,这些曲线以数学上定义的坐标点连接而成.具体到实现上,则需开发者提供一个xml格式的矢量图形定义,然后系统根据矢量定义自动计算该图形的绘制区域.因为绘图结果是动态计算得到,所以不管缩放到多少比例,矢量图形都会一样的清晰,不像位图那样拉大后会变模糊. 矢量图形的xml定义有点复杂,其结构

Android开发笔记(一百零七)统计分析SDK

APP统计分析 用户画像 对程序员来说,用户画像就是用户的属性和行为:通俗地说,用户画像是包括了个人信息.兴趣爱好.日常行为等血肉丰满的客户实体.用户画像是精准营销的产物,企业通过收集用户的行为,然后分析出用户的特征与偏好,进而挖掘潜在的商业价值,实现企业效益的最大化. 用户画像的一个具体应用是电商app的"猜你喜欢"栏目,电商平台通过对用户购买过的商品进行统计,可以分析用户日常生活用的是什么物品:电商平台还可以对用户的搜索行为.浏览行为进行统计,从中分析用户感兴趣的商品,或者说考虑购

Android开发笔记(一百零四)消息推送SDK

推送的集成 常用概念 推送:从服务器把消息实时发到客户端app上,这就是推送,推送可用于发送系统通知.发送推荐信息.发送聊天消息等等. 别名:用于给移动设备取个好记的名字,比如电脑有计算机名,可以把别名理解为开发者给移送设备起的外号.不过,多个移动设备可以起一样的别名,这几个设备就会同时收到发给该别名的消息. 标记:用于给移动设备打标签,可以理解为分类,比如超市里的泰国大米既可以打上"粮食制品"的标签,也可以打上"进口商品"的标签.服务器可以统一给某个种类的移动设备

Android开发笔记(一百零一)滑出式菜单

可移动页面MoveActivity 滑出式菜单从界面上看,像极了一个水平滚动视图HorizontalScrollView,当然也可以使用HorizontalScrollView来实现侧滑菜单.不过今天博主要说的是利用线性布局LinearLayout来实现,而且是水平方向上的线性布局. 可是LinearLayout作为水平展示时有点逗,因为如果下面有两个子视图的宽度都是match_parent,那么LinearLayout只会显示第一个子视图,第二个子视图却是怎么拉也死活显示不了.倘若在外侧加个H

Android开发笔记(一百零九)利用网盘实现云存储

网盘存储 个人开发者往往没有自己的后台服务器,但同时又想获取app的运行信息,这就要借助于第三方的网络存储(也叫网盘.云盘.微盘等等).通过让app自动在网盘上存取文件,可以间接实现后台服务器的存储功能,同时开发者也能及时找到app的用户信息. 曾几何时,各大公司纷纷推出免费的个人网盘服务,还开放了文件管理api给开发者调用,一时间涌现了网盘提供商的八大金刚:百度网盘.阿里云.华为网盘.腾讯微云.新浪微盘.360云盘.金山快盘.115网盘.可是好景不长,出于盈利.监管等等因素,各大网盘开放平台要

Android开发笔记(一百二十)两种侧滑布局

SlidingPaneLayout SlidingPaneLayout是Android在android-support-v4.jar中推出的一个可滑动面板的布局,在前面<Android开发笔记(一百零一)滑出式菜单>中,我们提到水平布局时的LinearLayout无法自动左右拉伸,必须借助于手势事件才能拉出左侧隐藏的布局,现在SlidingPaneLayout便是为了解决LinearLayout无法自动拉伸的缺陷.只要我们在布局文件的SlidingPaneLayout节点下定义两个子布局,那么