关于地图上使用的Overlay(类似遇见),加异步数据

遇见中使用百度地图可以在地图上显示头像功能,然后点击头像又会弹出气泡。
现在就来说一说这种效果的一种实现方式。 虽然我不知道他们如何处理的,但经过试验,效果差不多了。
使用的也是百度地图。
下载BaiduMapApi_Sample_Android_1.3.3.zip,目前官方最新版本。
直接使用里面的示例程序,ItemizedOverlayDemo就有气泡的效果,但里面的pop.png不是一个nine9patch文件,不能缩放。需要修改。
附件里面传一个可以缩放的图片。ps功底不好,图不是很好看。


新建一个Activity:TItemizedOverlay extends MapActivity,可以直接把示例中的复制过来。
修改里面的oncreate:overitem=new OverItemT(marker, this, 3);
//mMapView.getOverlays().add(overitem); //添加ItemizedOverlay实例到mMapView
不需要的是OverItemT。这是作为地图上的遮罩。

另外加入
Drawable markerDrawable=drawBitmap("test1");
mMapView.getOverlays().add(new MyOverItem(markerDrawable,TItemizedOverlay.this,new GeoPoint((int) (39.90923*1e6), (int) (116.397428*1e6))));
markerDrawable=drawBitmap("test2");
mMapView.getOverlays().add(new MyOverItem(markerDrawable,TItemizedOverlay.this,new GeoPoint((int) (39.90923*1e6), (int) (116.357428*1e6))));
markerDrawable=drawBitmap("test3");
mMapView.getOverlays().add(new MyOverItem(markerDrawable,TItemizedOverlay.this,new GeoPoint((int) (39.90923*1e6), (int) (116.437428*1e6))));
三个点覆盖层。
因为ItemizedOverlay的构造方法中,只能用Drawable,所以我们要做的是,生成一个Drawable,然后传入。现在先处理同步的,就是数据已经存在的了。后面再说异步下载图片,如何将新下载的图片做成Drawable,然后再放到地图上。
Drawable drawBitmap(String title){
Bitmap bmp = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.marker_view, null);
TextView titleView=(TextView) layout.findViewById(R.id.title);
titleView.setText(title);
layout.setDrawingCacheEnabled(true);
layout.measure(View.MeasureSpec.makeMeasureSpec(canvas.getWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(canvas.getHeight(), View.MeasureSpec.EXACTLY));
layout.layout(0, 0, layout.getMeasuredWidth(), layout.getMeasuredHeight());
Paint paint = new Paint();
canvas.drawBitmap(layout.getDrawingCache(), 0, 0, paint);

Drawable drawable = new BitmapDrawable(bmp);
return drawable;
}

这里通过布局文件引入,将需要的画成一个图。只是简单的处理画出来和图片大小是100*100的,动态的决定布局占用的大小更复杂一些。
因为遇见的效果就是一张图片。所以使用布局方面就可以简单的放一张图片,然后下面再有一张背景就可以了。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/pop_bg">

<TextView android:id="@+id/title" android:maxWidth="120dp"
android:text="testaa" android:textSize="20sp"
android:textColor="@android:color/black" android:padding="4dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>
这里使用的文字,如果文字太多,而没有处理实际需要的大小就不好看了。

然后一个Overlay
class MyOverItem extends ItemizedOverlay<OverlayItem> {

private Drawable marker;
private Context mContext;
GeoPoint mPoint;
OverlayItem mItem;

public MyOverItem(Drawable marker, Context context, GeoPoint point) {
//super(boundCenterBottom(marker));
super((marker));这里不要对齐,因为对齐后弹出的气泡会发生覆盖

this.marker=marker;
this.mContext=context;
mPoint=point;
mItem=new OverlayItem(point, "", "");

populate(); //createItem(int)方法构造item。一旦有了数据,在调用其它方法前,首先调用这个方法
}

@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {

super.draw(canvas, mapView, shadow);
//调整一个drawable边界,使得(0,0)是这个drawable底部最后一行中心的一个像素
//boundCenterBottom(marker);同样不能对齐
}

@Override
protected OverlayItem createItem(int i) {
return mItem;
}

@Override
public int size() {
return 1;
}

// 处理当点击事件
@Override
protected boolean onTap(int i) {//点击后就会弹出另一个气泡了。
setFocus(mItem);
// 更新气泡位置,并使之显示
TextView title=(TextView) mPopView.findViewById(R.id.title);
title.setText("lat:"+mPoint.getLatitudeE6()+" long:"+mPoint.getLongitudeE6());
mMapView.updateViewLayout(mPopView,
new MapView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
mPoint, MapView.LayoutParams.BOTTOM_CENTER));
mPopView.setVisibility(View.VISIBLE);
/*Toast.makeText(this.mContext, mItem.getSnippet(), Toast.LENGTH_SHORT).show();*/
return true;
}

@Override
public boolean onTap(GeoPoint arg0, MapView arg1) {
// 消去弹出的气泡
mPopView.setVisibility(View.GONE);
return super.onTap(arg0, arg1);
}
}

mPopView=super.getLayoutInflater().inflate(R.layout.popview, null);布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:padding="2.0dip"
android:background="@drawable/map_mark_bg" android:gravity="center_horizontal"
android:layout_width="54dp" android:layout_height="81dp">
这个高与宽需要指定,具体值与背景图片有关。就要是背景图片下面的三角形要显示出来。
<ImageView android:id="@+id/top_icon"
android:src="@drawable/ic_launcher"
android:layout_width="50dp" android:layout_height="50dp"/>
</LinearLayout>

最后的效果图就是:
[img]http://dl.iteye.com/upload/attachment/0071/5306/483e5585-88b2-354c-8780-56bedac54101.png[/img]
修改后的效果图:
[img]http://dl.iteye.com/upload/attachment/0071/5573/ee5fc596-1850-326b-96b2-3df67fb9a78f.png[/img]

除 了上面的之外,其实在地图上加一些点,不直接使用它的Overlay也是可以的,对每个点加一个点击事件,每个点放的位置坐标需要知道。由于放的是drawable不是layout,所以自定义方面复杂一点。

对于异步的处理;提供示例代码:
源码不是个人的,不能给的,认包涵。
提供思路:
oncreate()里面添加一个setMarker();方法
这个方法主要是执行数据的获取:
private void setMarker() {
new Thread(new Runnable() {
@Override
public void run() {
AssetManager assetManager=getAssets();
try {
InputStream inputStream=assetManager.open("store.json");
String js=HttpUtils.parseInputStream(inputStream);
ArrayList<StoreBean> storeBeans=JsonParser.parseStoreBeans(js);
updateOverlay(storeBeans);
在这里可以获取网络资源,也可以获取固定的资源,我不下载了,直接获取assets里面的
} catch (IOException e) {
e.printStackTrace();
} catch (T8Exception e) {
e.printStackTrace();
} finally {
//assetManager.close();
}
}

}).start();
}

private void updateOverlay(ArrayList<StoreBean> storeBeans) {
if(null==storeBeans||storeBeans.size()<1){
Log.d("","没有取得商店数据。");
return;
}

StoreBean first=storeBeans.get(0);
Message message=Message.obtain();
message.what=FIRST;//这里定义一个位置的中心,如果你在进入地图时已经有了中心点这就不需要了。
message.obj=first;
mHandler.sendMessage(message);

MyOverItem item;
ArrayList<MyOverItem> overItems=new ArrayList<MyOverItem>();
for (StoreBean bean : storeBeans) {
item=new MyOverItem(mMarkerDrawable, StoreMap.this, new GeoPoint((int) (bean.lat), (int) (bean.llong)), bean);
myOverItemHashMap.put(bean.url, item);
overItems.add(item);
}

if (overItems.size()>0) {
message=Message.obtain();
message.obj=overItems;
message.what=ALL;
mHandler.sendMessage(message);

Log.d("", "现在处理图片下载。");下面是模拟的,
try {
Thread.sleep(4000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
downloadAndUpdateOverlay(storeBeans);
}
}

主要的过程是:先获取地图上的点,如果没有坐标点,就没有标记了。这个数据来源可以在进入地图后获取,也可以在进入前intent带进来的。
2.获取地图的点后立即更新地图,并画上默认的图片。
3.异步线程获取地图点对应的图片或其它数据。
4.更新异步线程获取的地图点对应的数据,就可以展现出气泡了。

这里采用了单线程来处理多个图片资源的下载,如果网络慢的话,可能图片的展示也慢,可以使用线程池来处理。
private void downloadAndUpdateOverlay(ArrayList<StoreBean> storeBeans) {
for (StoreBean bean : storeBeans) {
try {
if (!loadImg) {
break;
}
Log.d("", "bean:"+bean);
String url=bean.url;

Bitmap img=App.getmImageLoader(StoreMap.this).getLargeBitmap(url, App.mCacheDir);

Drawable markerDrawable;
MyOverItem myOverItem;
Message message;
if (null!=img) {
markerDrawable=drawBitmapLayout(img);
myOverItem=new MyOverItem(markerDrawable, StoreMap.this, new GeoPoint((int) (bean.lat), (int) (bean.llong)), bean);
message=Message.obtain();
message.what=OTHER;//表示非定位的点,如果在进入地图已经获取了中心点,这里就直接处理为普通的坐标点就可以了。
message.obj=myOverItem;
mHandler.sendMessage(message);
}

myOverItemHashMap.remove(bean.url);移除已经下载的坐标点。
} catch (Exception e) {
e.printStackTrace();
}
}
}

Handler mHandler=new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int what=msg.what;
switch (what) {
case FIRST:
try {
StoreBean bean=(StoreBean) msg.obj;
mMapView.getController().setCenter(new GeoPoint((int) bean.lat, (int) bean.llong));
} catch (Exception e) {
e.printStackTrace();
}
break;

case OTHER: {
MyOverItem myOverItem=(MyOverItem) msg.obj;
mMapView.getOverlays().add(myOverItem);
mMapView.postInvalidate();
break;
}

case ALL:
ArrayList<MyOverItem> myOverItems=(ArrayList<MyOverItem>) msg.obj;
mMapView.getOverlays().addAll(myOverItems);
mMapView.postInvalidate();
break;

case UPDATE: {
MyOverItem myOverItem=(MyOverItem) msg.obj;
List<Overlay> overlays=mMapView.getOverlays();
MyOverItem item;
Overlay overlay;
for (int i=0; i<overlays.size(); i++) {
overlay=overlays.get(i);
if (overlay instanceof MyOverItem) {
item=(MyOverItem) overlay;
if (item.mBean.id==myOverItem.mBean.id) {
Log.d("", "更新的覆盖物是:"+myOverItem);
overlays.remove(i);
mMapView.getOverlays().add(myOverItem);
mMapView.postInvalidate();
break;
}
}
}
break;
}
}
}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值