之前做了一个图片处理的app,把本地图片的经纬度存到手机本地数据库,然后在app中的“图片位置”页面的地图上的对应位置显示该图片,并有点聚合功能,能动态调整地图展示整屏Marker。效果如下:
本功能使用的是高德地图的API,是在高德“点聚合效果”demo的基础上改的(高德官网提供的聚合点demo下载),下面的代码里很多类用的都是这个demo上的,如果缺少类请在demo里找。加载的图片都是手机本地的图片。点击自定义marker图片会获取该点聚合下的所有图片路径。
在工程-app下的build.gradle中添加高德地图的依赖:
//高德3d地图
compile 'com.amap.api:3dmap:5.6.0'
compile 'com.amap.api:map2d:5.2.0'
//定位
compile 'com.amap.api:location:3.7.0'
compile 'com.amap.api:search:5.5.0'
在要展示点聚合页面的activity里:
@Override
protected void onResume() {
super.onResume();
mapView.onResume();//方法必须重写
//清空之前的数据,重新获取数据。
clusterItems.clear();
pointList.clear();
uriList.clear();
addresList.clear();
getPointList();
mClusterOverlay = new ClusterOverlay(aMap,clusterItems,dip2px(getApplicationContext(),clusterRadius),getApplicationContext());
mClusterOverlay.setClusterRenderer(this);
mClusterOverlay.setOnClusterClickListener(this);
}
private int clusterRadius = 60;//聚合范围的大小(指点像素单位距离内的点会聚合到一个点显示)
private MarkerOverlay markerOverlay;
private ClusterOverlay mClusterOverlay;
private List<LatLng> pointList = new ArrayList<>();//图片的经纬度list
private List<String> uriList = new ArrayList<>();//图片的URI list
private List<ClusterItem> clusterItems=new ArrayList<>();//聚合元素的list。ClusterItem是高德点聚合demo里的类,是点聚合的bean
private List<LocalFile> addresList = new ArrayList<>();//
//获取要显示的marker的经纬度集合
private List<LatLng> getPointList() {
addresList = helper.queryAddressDate();//从数据库获取含有经纬度的图片的list
for (LocalFile localFile : addresList) {
String dateStr = localFile.getDateStr();
int mediaId = localFile.getMediaID();
String originalUri = localFile.getOriginalUri();
LatLng latLng = new LatLng(localFile.getLatitude(),localFile.getLongitude());
RegionItem regionItem = new RegionItem(latLng,"",originalUri,mediaId);
clusterItems.add(regionItem);
pointList.add(latLng);
uriList.add(originalUri);
}
return pointList;
}
//方法必须重写
@Override
protected void onDestroy() {
super.onDestroy();
if(markerOverlay!=null) {
markerOverlay.removeFromMap();
if (locationClient != null) {
locationClient.onDestroy();
locationClient = null;
locationClientOption = null;
}
}
if(mClusterOverlay != null) {
mClusterOverlay.onDestroy();
}
if(mapView!=null) {
mapView.onDestroy();
}
}
//点击点聚合图片,会获取该点聚合下的所有图片信息
@Override
public void onClusterClick(Marker marker, List<ClusterItem> clusterItems) {
Log.e("onClusterClick",clusterItems.toString()+",mediaId="+clusterItems.get(0).getMediaId());
List<LocalFile> addrFileList=new ArrayList<>();
LocalFile localFile;
for (ClusterItem clusterItem : clusterItems){
localFile=new LocalFile();
localFile.setMediaID(clusterItem.getMediaId());
localFile.setOriginalUri(clusterItem.getUriStr());
addrFileList.add(localFile);
}
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(MY_ADDR_LIST, (ArrayList<? extends Parcelable>) addrFileList);
ActivityHelper.jumpWithBundleNoFinish(this,MyAddressListActivity.class,bundle);
//点击会继续放大地图
/* LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (ClusterItem clusterItem:clusterItems){
builder.include(clusterItem.getPosition());
}
LatLngBounds latLngBounds = builder.build();
aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds,0));*/
}
下面的代码是ClusterOverlay.java内的,ClusterOverlay类是点聚合的关键类,自定义的点聚合marker图片就在这部分。
private List<Marker> mAddMarkers = new ArrayList<Marker>();
/**
* 将聚合元素添加至地图上
*/
private void addClusterToMap(List<Cluster> clusters) {
ArrayList<Marker> removeMarkers = new ArrayList<>();
removeMarkers.addAll(mAddMarkers);
// AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);//移动地图时marker图片会闪烁
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 1);
MyAnimationListener myAnimationListener = new MyAnimationListener(removeMarkers);
for (Marker marker : removeMarkers) {
marker.setAnimation(alphaAnimation);
marker.setAnimationListener(myAnimationListener);
marker.startAnimation();
}
// Map map = new HashMap();
List<Bitmap> bitmapList=new ArrayList<>();
for (int i=0;i<clusters.size();i++){
Cluster cluster=clusters.get(i);
String uriStr = cluster.getClusterItems().get(0).getUriStr();
Log.e("icon=",uriStr);
//根据图片的uri获取图片的绝对路径
String imgPath = getRealPathFromUri(mContext, Uri.parse(uriStr));
Bitmap bitmap = getImgCompressBitmapByFileDescriptor(imgPath);
// map.put(i,bitmap);
bitmapList.add(bitmap);
}
for (int i=0;i<bitmapList.size();i++){
addSingleClusterToMap(clusters.get(i),bitmapList.get(i));
}
/*for (Cluster cluster : clusters) {
addSingleClusterToMap(cluster);
}*/
}
/**
* 将单个聚合元素添加至地图显示
* @param cluster
*/
private void addSingleClusterToMap(Cluster cluster, Bitmap bitmap) {
int clusterCount = cluster.getClusterCount();//点聚合的数量
String clusterNum=String.valueOf(clusterCount);
//如果数量超过99张,则显示99+
if(clusterCount>99) {
clusterNum="99+";
}
//点聚合的页面布局,就是自定义的点聚合部分
View view = View.inflate(mContext, R.layout.view_poi_overlay_item, null);
//CircleImageView是自定义的圆形imageview
CircleImageView ivPoiImg = (CircleImageView) view.findViewById(R.id.iv_poi_img);
TextView tvNum = (TextView) view.findViewById(R.id.tv_num);
tvNum.setText(clusterNum);//要把int类型转换为String类型,否则会误认为是resourceId报异常。
ivPoiImg.setImageBitmap(bitmap);
LatLng latlng = cluster.getCenterLatLng();
MarkerOptions markerOptions = new MarkerOptions();
// markerOptions.anchor(0.5f, 0.5f).icon(getBitmapDes(cluster.getClusterCount())).position(latlng);
markerOptions.anchor(0.5f, 0.5f).icon(BitmapDescriptorFactory.fromView(view)).position(latlng);
Marker marker = mAMap.addMarker(markerOptions);
// marker.setAnimation(mADDAnimation);
marker.setObject(cluster);
// marker.startAnimation();
cluster.setMarker(marker);
mAddMarkers.add(marker);
}
自定义点聚合marker图片的布局文件view_poi_overlay_item.xml,其中CircleImageView引用于compile 'de.hdodenhof:circleimageview:2.2.0',控件的宽高可以自己设定,不必按照下面从dimens文件里引用的:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/poi_item_width_height"
android:layout_height="@dimen/poi_item_width_height"
android:id="@+id/rl_poi_img_bg">
<de.hdodenhof.circleimageview.CircleImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/iv_poi_img"
android:layout_width="@dimen/poi_item_width_height"
android:layout_height="@dimen/poi_item_width_height"
android:src="@mipmap/ic_launcher"
app:civ_border_width="@dimen/my_header_border_size"
app:civ_border_color="@color/white"
android:layout_centerHorizontal="true"/>
<TextView
android:id="@+id/tv_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:background="@drawable/tv_badge"
android:text="99"
android:padding="2dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="@dimen/text_size_9"/>
</RelativeLayout>
点聚合数字的样式tv_badge.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:useLevel="false">
<solid android:color="@color/orange_normal"/>
<size android:width="@dimen/poi_text_badge_w_h"
android:height="@dimen/poi_text_badge_w_h"/>
</shape>
另外MarkerOverlay.java里的addToMap()方法也要添加自定义的marker图片布局:
/**
* 添加Marker到地图中。
*/
public void addToMap(final List<String> uriList) {
try {
final Runnable runnable = new Runnable() {
@Override
public void run() {
View view;
CircleImageView ivPoiImg;
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(context));
for (int i = 0; i < pointList.size(); i++) {
final LatLng latLng = pointList.get(i);
// view = View.inflate(context, R.layout.view_poi_overlay_item, null);
// ivPoiImg = (CircleImageView) view.findViewById(R.id.iv_poi_img);
Log.e(TAG, "addToMap,uriList.get(i):" + uriList.get(i) + ",pointList.get(i):" + pointList.get(i));
Uri imgUri = Uri.parse(uriList.get(i));
String realPath = getRealPathFromUri(context, imgUri);
Log.e(TAG, "realPath:" + realPath + ",imgUri:" + imgUri);
final int finalI = i;
imageLoader.loadImage(uriList.get(i), new SimpleImageLoadingListener() {
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
view = View.inflate(context, R.layout.view_poi_overlay_item, null);
CircleImageView ivPoiImg = (CircleImageView) view.findViewById(R.id.iv_poi_img);
ivPoiImg.setImageBitmap(loadedImage);
final Marker marker = aMap.addMarker(new MarkerOptions()
.position(latLng)
// .icon(BitmapDescriptorFactory.fromResource(R.mipmap.bg_poi_overlay)));
.icon(BitmapDescriptorFactory.fromView(view)));
// .icon(BitmapDescriptorFactory.fromBitmap(realPath)));
// .icon(getBitmapDescriptor(context,i,uriList)));
marker.setObject(finalI);
mMarkers.add(marker);
}
});
/*Glide.with(context)
.load(uriList.get(i))
.crossFade()
.placeholder(R.drawable.detailpic_no)
.error(R.drawable.error)
.thumbnail(0.1f)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(new SimpleTarget<GlideDrawable>() {
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
View view = View.inflate(context, R.layout.view_poi_overlay_item, null);
CircleImageView ivPoiImg = (CircleImageView) view.findViewById(R.id.iv_poi_img);
//会oom
ivPoiImg.setImageBitmap(drawableToBitmap(resource));
final Marker marker = aMap.addMarker(new MarkerOptions()
.position(latLng)
.icon(BitmapDescriptorFactory.fromView(view)));
marker.setObject(finalI);
mMarkers.add(marker);
}
});*/
}
}
};
new Thread(){
public void run(){
//不写会Can't create handler inside thread that has not called Looper.prepare()
new Handler(Looper.getMainLooper()).post(runnable);
}
}.start();
} catch (Throwable e) {
e.printStackTrace();
}
}
这样基本上已经完成了。
说明:源码中LocalImageHelper是数据库操作类,就是对数据库的增删改查。这个自己写吧,就不贴我的代码了。代码中这个类是查找数据库中图片bean的集合,然后在地图中显示。