前段时间搞高德地图,集成地图后,发现如果把地图这块放在view里面,不便于后期的维护,想着封装一个,把地图有关的方法,专门放一个类,同时也方便以后的偷懒☺.Let's Go!
显示地图
public class MapActivity extends AppCompatActivity {
@InjectView(R.id.mapView)
MapView mMapView;
private AMap aMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
// 使用黄油刀注解找控件
ButterKnife.inject(this);
initMap(savedInstanceState);
}
private void initMap(Bundle savedInstanceState) {
mMapView.onCreate(savedInstanceState);
aMap = null;
if (aMap == null) {
aMap = mMapView.getMap();
}
// 显示地图
MapUtil.getInstance().initMap(aMap, this);
}
@Override
public void onDestroy() {
super.onDestroy();
// 在activity执行onDestroy时执行mMapView.onDestroy(),销毁地图
mMapView.onDestroy();
}
@Override
public void onResume() {
super.onResume();
// 在activity执行onResume时执行mMapView.onResume (),重新绘制加载地图
mMapView.onResume();
}
@Override
public void onPause() {
super.onPause();
// 在activity执行onPause时执行mMapView.onPause (),暂停地图的绘制
mMapView.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// 在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState (outState),保存地图当前的状态
mMapView.onSaveInstanceState(outState);
}
}
除了地图相关的配置外,你只需要 MapUtil.getInstance().initMap(aMap, this);一行代码就可以实现,够简洁吧!下面我们看下,内部的实现
// 单例没啥好说的
private static MapUtil sMapUtil;
private LatLng mLatLng;
private MapUtil() {
}
![![微信图片_20180519135100.jpg](https://upload-images.jianshu.io/upload_images/5286943-34dfb6ace9ea966b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
](https://upload-images.jianshu.io/upload_images/5286943-5ea74273e21ca41f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
public static MapUtil getInstance() {
if (sMapUtil == null) {
synchronized (MapUtil.class) {
if (sMapUtil == null) {
sMapUtil = new MapUtil();
}
}
}
return sMapUtil;
}
// 初始化地图,关键代码
public MapUtil initMap(AMap aMap, Context context) {
this.aMap = aMap;
this.mContext = context;
mlocationClient = new AMapLocationClient(context);
//初始化定位参数
mLocationOption = new AMapLocationClientOption();
//设置定位监听
mlocationClient.setLocationListener(this);
//设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//设置定位间隔,单位毫秒,默认为2000ms
mLocationOption.setInterval(3000);
//设置定位参数
mlocationClient.setLocationOption(mLocationOption);
// 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
// 注意设置合适的定位时间的间隔(最小间隔支持为1000ms),并且在合适时间调用stopLocation()方法来取消定位请求
// 在定位结束后,在合适的生命周期调用onDestroy()方法
// 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
//启动定位
mlocationClient.startLocation();
// TODO: 2018/5/13 地图的层级大小,可以对外暴露
aMap.moveCamera(CameraUpdateFactory.zoomTo(19));
// 显示定位蓝点
initPoint();
// 去掉右边缩放按钮
aMap.getUiSettings().setZoomControlsEnabled(false);
aMap.setOnCameraChangeListener(this);
return this;
}
// 自定义定位蓝点
public void initPoint() {
MyLocationStyle myLocationStyle;
myLocationStyle = new MyLocationStyle();//初始化定位蓝点样式类myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);//连续定位、且将视角移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。(1秒1次定位)如果不设置myLocationType,默认也会执行此种模式。
myLocationStyle.interval(2000); //设置连续定位模式下的定位间隔,只在连续定位模式下生效,单次定位模式下不会生效。单位为毫秒。
// 设置边框的颜色
myLocationStyle.strokeColor(Color.TRANSPARENT);
// 设置边框的填充色
myLocationStyle.radiusFillColor(Color.TRANSPARENT);
// 设置定位点图片
myLocationStyle.myLocationIcon(getBitmapDescriptor(R.mipmap.icon_location_blue));
// 定位一次,且将视角移动到地图中心点
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER);
aMap.setMyLocationStyle(myLocationStyle);//设置定位蓝点的Style
//aMap.getUiSettings().setMyLocationButtonEnabled(true);设置默认定位按钮是否显示,非必需设置。
aMap.setMyLocationEnabled(true);// 设置为true表示启动显示定位蓝点,false表示隐藏定位蓝点并不进行定位,默认是false。
// 因为模式问题,所以要手动调用
if (mLatLng != null) {
aMap.moveCamera(CameraUpdateFactory.changeLatLng(mLatLng));
}
}
绘制Marker点
private void initMap(Bundle savedInstanceState) {
mMapView.onCreate(savedInstanceState);
aMap = null;
if (aMap == null) {
aMap = mMapView.getMap();
}
// 显示地图,设置地图回调
MapUtil.getInstance().initMap(aMap, this).setMapRefreshListener(this);
}
public void drawMarker(LatLng latLng) {
// 模拟数据集合
List<LatLng> markerList = new ArrayList<>();
for (int i = 0; i < 4; i++) {
double longitude = latLng.longitude + ((i + 1) * 0.0001);
double latitude = latLng.latitude + ((i + 1) * 0.0001);
markerList.add(new LatLng(latitude, longitude));
}
// 绘制Marker集合
MapUtil.getInstance().addAllMarker(markerList);
// 绘制Marker点
MapUtil.getInstance().addMarker(latLng);
}
/**
* 得到经纬度
* @param latLng
*/
@Override
public void getLatLng(LatLng latLng) {
// 绘制marker
drawMarker(latLng);
}
MapUtil
public void addAllMarker(List<LatLng> latLngList) {
for (LatLng latLng : latLngList) {
addMarker(latLng);
}
}
public void addMarker(LatLng latLng) {
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
// TODO: 2018/5/13 如果是复杂的,可以把布局转成bitmap
// View view = View.inflate(mContext, R.layout.marker, null);
// Bitmap bitmap = convertViewToBitmap(view);
// 自定义图片
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
.decodeResource(mContext.getResources(), R.mipmap.icon_taskcar_get)));
// markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap));
Marker marker = aMap.addMarker(markerOptions);
mMarkerSparseArray.put(mMarkerSparseArray.size(), marker);
marker.showInfoWindow();
// 是否需要显示弹窗
infoWindow();
}
Marker点的点击事件
// 由于第一次点击也会走地图的回调,所以要加个开关
private boolean toggle = false;
// 定义 Marker [图片上传中...(31bcedde8ed5d0abf39d165177c83736.gif-b70360-1526708414566-0)]
点击事件监听
AMap.OnMarkerClickListener markerClickListener = new AMap.OnMarkerClickListener() {
// marker 对象被点击时回调的接口
// 返回 true 则表示接口已响应事件,否则返回false
@Override
public boolean onMarkerClick(Marker marker) {
mMarker = marker;
toggle = true;
MapUtil.getInstance().addInfoWindow(marker);
return false;
}
};
private void initMap(Bundle savedInstanceState) {
mMapView.onCreate(savedInstanceState);
// 使用黄油刀注解找控件
aMap = null;
if (aMap == null) {
aMap = mMapView.getMap();
}
// 显示地图,设置地图回调
MapUtil.getInstance().initMap(aMap, this).setMapRefreshListener(this);
// 实现地图的监听
aMap.setOnMapClickListener(new AMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng latLng) {
if (!toggle && mMarker != null) {
MapUtil.getInstance().removeInfoWindow(mMarker);
mMarker = null;
}
toggle = false;
}
});
// 实现marker的监听
aMap.setOnMarkerClickListener(markerClickListener);
}
MapUtil
/**
* 添加移除infoWindow
* @param marker
*/
public void addInfoWindow(Marker marker) {
marker.setInfoWindowEnable(true);
}
/**
* 移除infoWindow
* @param marker
*/
public void removeInfoWindow(Marker marker) {
marker.setInfoWindowEnable(false);
}
绘制矩形
/**
* 得到经纬度
*
* @param latLng
*/
@Override
public void getLatLng(LatLng latLng) {
// 绘制marker
drawMarker(latLng);
// 绘制线
drawRectangle(latLng);
}
private void drawRectangle(LatLng latLng) {
MapUtil.getInstance().addRectangle(latLng);
}
MapUtil
public void addRectangle(LatLng latLng) {
// 绘制一个长方形
aMap.addPolygon(new PolygonOptions()
.addAll(createRectangle(latLng, 0.0001, 0.0001))
.fillColor(Color.parseColor("#FFCBCB"))
// 线的宽度取消
.strokeWidth(0)
);
// 虚线组成一个长方形
aMap.addPolyline(new PolylineOptions()
.addAll(createRectangle(latLng, 0.0001, 0.0001))
.width(10)
.setDottedLine(true)
.color(Color.parseColor("#F45A5A")));
}
public void addRectangle(List<LatLng> latLngList) {
// 绘制一个长方形
aMap.addPolygon(new PolygonOptions()
.addAll(latLngList)
.fillColor(Color.parseColor("#4DBDEDFF"))
// 线的宽度取消
.strokeWidth(0)
);
// 虚线组成一个长方形
aMap.addPolyline(new PolylineOptions()
.addAll(latLngList)
.width(10)
.setDottedLine(true)
.color(Color.parseColor("#3BC3F5")));
}
/**
* 生成一个长方形的四个坐标点
*/
private List<LatLng> createRectangle(LatLng center, double halfWidth, double halfHeight) {
List<LatLng> latLngs = new ArrayList<LatLng>();
// TODO: 2018/5/19 添加最后一个点,组成闭合,不然会少一边
latLngs.add(new LatLng(center.latitude + halfHeight, center.longitude - halfWidth));
// 矩形的四个点
latLngs.add(new LatLng(center.latitude - halfHeight, center.longitude - halfWidth));
latLngs.add(new LatLng(center.latitude - halfHeight, center.longitude + halfWidth));
latLngs.add(new LatLng(center.latitude + halfHeight, center.longitude + halfWidth));
latLngs.add(new LatLng(center.latitude + halfHeight, center.longitude - halfWidth));
return latLngs;
}
这里要注意:画矩形要给5个点,第一个和最后一个点一样,文档上是4个点,会少一边
移动指定距离刷新地图
@Override
public void onCameraChange(CameraPosition cameraPosition) {
}
@Override
public void onCameraChangeFinish(CameraPosition cameraPosition) {
LatLng currentLatlng = cameraPosition.target;
double distance = AMapUtils.calculateLineDistance(preLatlng, currentLatlng);
totalDistance = distance;
Log.d(TAG, "onCameraChange: 距离" + totalDistance);
if (totalDistance >= REFRESH_DISTANCE) {
if (firstChange) {
firstChange = false;
return;
}
preLatlng = currentLatlng;
Log.d(TAG, "onCameraChange: 要刷新了");
totalDistance = 0;
if (mMapListener != null) {
mMapListener.refresh();
}
}
}
监听地图中心点的位置,和起始点位置,获取距离,如果大于,就把当前点记录,这里要注意的是,刚开始的时候位置会偏移很大,排除第一次的
重置指南针
MapActivity没什么好说的
@OnClick(R.id.iv_location)
public void onViewClicked() {
MapUtil.getInstance().initPoint();
}
MapUtil
// 开启指南针
// 初始化地图,关键代码
public MapUtil initMap(AMap aMap, Context context, int getZoomB) {
this.aMap = aMap;
this.mContext = context;
mlocationClient = new AMapLocationClient(context);
//初始化定位参数
mLocationOption = new AMapLocationClientOption();
//设置定位监听
mlocationClient.setLocationListener(this);
//设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//设置定位间隔,单位毫秒,默认为2000ms
mLocationOption.setInterval(3000);
//设置定位参数
mlocationClient.setLocationOption(mLocationOption);
// 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
// 注意设置合适的定位时间的间隔(最小间隔支持为1000ms),并且在合适时间调用stopLocation()方法来取消定位请求
// 在定位结束后,在合适的生命周期调用onDestroy()方法
// 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
//启动定位
mlocationClient.startLocation();
// 显示定位蓝点
initPoint();
// 去掉右边缩放按钮
aMap.getUiSettings().setZoomControlsEnabled(false);
aMap.setOnCameraChangeListener(this);
// 开启指南针
aMap.getUiSettings().setCompassEnabled(true);
return this;
}
// 自定义定位蓝点
public void initPoint() {
MyLocationStyle myLocationStyle;
myLocationStyle = new MyLocationStyle();//初始化定位蓝点样式类myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);//连续定位、且将视角移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。(1秒1次定位)如果不设置myLocationType,默认也会执行此种模式。
myLocationStyle.interval(2000); //设置连续定位模式下的定位间隔,只在连续定位模式下生效,单次定位模式下不会生效。单位为毫秒。
// 设置边框的颜色
myLocationStyle.strokeColor(Color.TRANSPARENT);
// 设置边框的填充色
myLocationStyle.radiusFillColor(Color.TRANSPARENT);
// 设置定位点图片
myLocationStyle.myLocationIcon(getBitmapDescriptor(R.mipmap.icon_location_blue));
// 定位一次,且将视角移动到地图中心点
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER);
aMap.setMyLocationStyle(myLocationStyle);//设置定位蓝点的Style
//aMap.getUiSettings().setMyLocationButtonEnabled(true);设置默认定位按钮是否显示,非必需设置。
aMap.setMyLocationEnabled(true);// 设置为true表示启动显示定位蓝点,false表示隐藏定位蓝点并不进行定位,默认是false。
// 因为模式问题,所以要手动调用
if (mLatLng != null) {
aMap.moveCamera(CameraUpdateFactory.changeLatLng(mLatLng));
}
// 地图的层级大小
aMap.moveCamera(CameraUpdateFactory.zoomTo(getZoomB));
// TODO: 2018/5/21 0021 重置指南针位置,找了好久
if (mLatLng != null) {
float bearing = 0.0f; // 地图默认方向
float tilt = 0.0f; // 地图默认方向
aMap.animateCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition(mLatLng, getZoomB, tilt, bearing)));
}
}