Android地图开发:自定义地图弹出框内容
2012-04-10 18:08
495 查看
Android地图开发有个很常见的需求,比如地图上绘制一系列图标,点击每个图标,弹出一个气泡,里面是详细内容,有图片、文字等等。
这篇文章讲的是如何自定义一个弹出框,里面包含图片、文字等等,思路是这样的:
我们写一个弹出框的xml布局文件,需要弹出的时候,将这个view转换成bitmap,然后转换成drawable,然后就可以控制这个drawable的位置,比如让它显示在图标的上方,当然可以随意设定弹出的位置。
我们先看看效果图:
地图使用的是图吧的地图,实际上Google Maps也是一样的,API调用方法都一样的,只是图吧地图xml布局里面不需要key。
上图中弹出的气泡时间上是一个LinearLayout,只是将其转换成了drawable,以便使用canvas绘制。
这里我们分成两个部分讲,分成两个类,MapPopupActivity(地图页面)和MapPopupView(弹出框)。
1.首先,我们准备好地图,在此地图上我们将绘制一系列图标,点击图标时弹出气泡。内容有点多,我会进行注释。
MapPopupActivity.java
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import com.mapbar.android.maps.*;
import com.tuan800.credit.R;
import com.tuan800.credit.views.MapPopupView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: chenjishi
* Date: 12-4-10
* Time: 下午4:29
* To change this template use File | Settings | File Templates.
*/
public class MapPopupActivity extends MapActivity implements MapPopupView.PopupViewTapListener {
private List<Spot> mSpotList;
private MapView mMapView;
private MapController mMapController;
private List<Overlay> mOverlayList;
private OverItemT mOverItemT;
//弹出窗口类
private MapPopupView mMapPopupView;
//设定一个地图中心位置
private double mLat = 39.973860D;
private double mLng = 116.382240D;
private Resources mRes;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.map_view);
mMapView = (MapView) this.findViewById(R.id.map_view);
mMapView.setBuiltInZoomControls(true);
mMapController = mMapView.getController();
mMapController.setZoom(12);
mRes = getResources();
//默认图标
Drawable defaultIcon = mRes.getDrawable(R.drawable.my_location);
defaultIcon.setBounds(0, 0, defaultIcon.getIntrinsicWidth(), defaultIcon.getIntrinsicHeight());
//绘制图标的内部类
mOverItemT = new OverItemT(defaultIcon);
//初始化弹出窗
mMapPopupView = new MapPopupView(this, mRes.getDrawable(R.drawable.category_1));
//处理弹出窗的点击事件
mMapPopupView.setPopupViewListener(this);
mOverlayList = mMapView.getOverlays();
//下面这两句很重要,不然图标无法显示
mOverlayList.add(mOverItemT);
mOverlayList.add(mMapPopupView);
//设置地图中心点
setMyLocation();
//初始化一系列图标
setData();
//往地图上绘制图标
setMarkers();
}
private void setMyLocation() {
GeoPoint p = new GeoPoint((int) (mLat * 1E6), (int) (mLng * 1E6));
mOverItemT.addOverlay(new OverlayItem(p, "我的位置", ""), 0);
mMapController.setCenter(p);
}
private void setMarkers() {
if (mSpotList.size() == 0) {
return;
}
for (Spot spot : mSpotList) {
GeoPoint point = new GeoPoint((int) (spot.lat * 1E6), (int) (spot.lng * 1E6));
OverlayItem item = new OverlayItem(point, spot.title, spot.detail);
mOverItemT.addOverlay(item, spot.categoryId);
}
}
@Override
public void onPopupViewTap() {
//点击弹窗时让其消失
mMapPopupView.dismiss();
}
//内部类,负责图标的绘制
class OverItemT extends ItemizedOverlay<OverlayItem> {
//每一个OverlayItem就是一个图标
ArrayList<OverlayItem> itemList = new ArrayList<OverlayItem>();
public OverItemT(Drawable drawable) {
super(boundCenterBottom(drawable));
}
public void addOverlay(OverlayItem item, int idx) {
if (item == null) return;
//这里我们根据spot的id分配不同的图标
Drawable icon;
int iconIdx = R.drawable.my_location;
if (idx >= 1 && idx <= 4) {
iconIdx = mRes.getIdentifier("drawable/category_" + idx, null, getPackageName());
}
icon = mRes.getDrawable(iconIdx);
item.setMarker(icon);
boundCenterBottom(icon);
itemList.add(item);
populate();
}
@Override
protected OverlayItem createItem(int i) {
return itemList.get(i);
}
@Override
public int size() {
return itemList.size();
}
//这里负责图标点击事件,如果点击的是当前位置,不弹窗,当前位置i=0,每一次点击时,我们将其他的弹窗关掉,本类中只存在一个弹窗类对象。
@Override
protected boolean onTap(int i) {
mMapPopupView.dismiss();
if (i == 0) return true;
OverlayItem item = itemList.get(i);
setFocus(item);
//int数组2,3是弹窗图标索引,这里我们将在弹窗里面绘制两个图标
mMapPopupView.addOverlay(item, new int[]{2, 3});
mMapController.animateTo(item.getPoint());
return true;
}
//这里是点击图标之外的区域,让已经显示的弹窗消失。
@Override
public boolean onTap(GeoPoint geoPoint, MapView mapView) {
if (!super.onTap(geoPoint, mapView)) {
mMapPopupView.dismiss();
}
return true;
}
//super.draw(canvas, mapView, false);false代表不绘制阴影
@Override
public void draw(Canvas canvas, MapView mapView, boolean b) {
super.draw(canvas, mapView, false);
}
}
private void setData() {
mSpotList = new ArrayList<Spot>();
String[] names = {
"宏状元粥店(健德门店)",
"非尝羊蝎子(马甸店)",
"非尝羊蝎子婆婆鱼",
"天丽姿美容(双安店",
"牛魔王拉面(健德门店)",
"福美炫彩电玩台球俱乐部",
"福美炫彩电玩城",
"华乐文化艺术培训中心(马甸校区)",
"清香阁(健德门桥店)",
"芭斯罗缤(北辰世纪店)",
"北京雅谛思艺术培训",
"食尚芭萨西饼屋",
"清香阁(健德门桥店)",
"非尝羊蝎子婆婆鱼"
};
String[] lats = {
"39.973831",
"39.97335",
"39.97625",
"39.975761",
"39.976719",
"39.975848",
"39.975761",
"39.976719",
"39.927289",
"39.976719",
"39.97656",
"39.976586",
"39.972751",
"39.977435"
};
String[] lngs = {
"116.381906",
"116.383853",
"116.38121",
"116.379047",
"116.379857",
"116.380286",
"116.379047",
"116.379857",
"116.291042",
"116.379857",
"116.37946",
"116.385382",
"116.386314",
"116.386266"
};
for (int i = 0; i < lngs.length; i++) {
Spot spot = new Spot();
spot.title = names[i];
spot.lat = Double.parseDouble(lats[i]);
spot.lng = Double.parseDouble(lngs[i]);
spot.categoryId = (i % 4) + 1;
spot.detail = "仅售9元,新辣道梭边鱼随你吃!新辣道+拉手网!本单所售全部款项将全部捐给芒果V基金,用于四川凉山贫困儿童救助事业,全国47家店通用,亲,只有抢到了才有机会喔!须为新辣道会员,每桌1名会员即可,如无会员卡,可在门店办理,4月2、3、4、7、8、14、15日拉手券不可使用!锅底需到店另付!";
mSpotList.add(spot);
}
}
private class Spot {
public String title;
public String detail;
public double lat;
public double lng;
public int categoryId;
}
}
2.弹窗类,首先inflat出弹窗内容的view,根据overlayitem的title,detail,设置文字,根据传进来的int数组动态生成图片。
public class MapPopupView extends ItemizedOverlay<OverlayItem> {
OverlayItem mOverlayItem;
Paint mPaint;
//图标的高度,这样我们就可以将气泡偏移这个高度,让气泡放置在图标之上而不遮盖图标
int mIconHeight;
//气泡的xml布局,稍后我们会放在后面贴上
LinearLayout mPopupView;
TextView mPopTitle;
TextView mPopDetail;
LinearLayout mIcons;
Context mContext;
PopupViewTapListener listener;
public MapPopupView(Context context, Drawable drawable) {
super(boundCenterBottom(drawable));
mContext = context;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPopupView = (LinearLayout) inflater.inflate(R.layout.map_popup_view, null);
mPopTitle = (TextView) mPopupView.findViewById(R.id.tv_popup_title);
mPopDetail = (TextView) mPopupView.findViewById(R.id.tv_popup_detail);
mIcons = (LinearLayout) mPopupView.findViewById(R.id.ll_popup_icon);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mIconHeight = drawable.getIntrinsicHeight();
populate();
}
public void setPopupViewListener(PopupViewTapListener listener) {
this.listener = listener;
}
@Override
protected OverlayItem createItem(int i) {
return mOverlayItem;
}
@Override
public int size() {
return mOverlayItem == null ? 0 : 1;
}
public void addOverlay(OverlayItem item, int[] bankIds) {
if (item == null) return;
//设置标题
mPopTitle.setText(item.getTitle());
//生成银行icon
if (bankIds != null && bankIds.length > 0) {
mIcons.setVisibility(View.VISIBLE);
mIcons.removeAllViews();
for (int i : bankIds) {
int iconIdx = mContext.getResources().getIdentifier("drawable/bank_" + i, null, mContext.getPackageName());
ImageView iv = new ImageView(mContext);
iv.setImageResource(iconIdx);
mIcons.addView(iv, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
//设置内容,为了防止内容过长,我们让文字这行,显示15个字,两行就够了
String detail = item.getSnippet();
if (!TextUtils.isEmpty(detail)) {
mPopDetail.setVisibility(View.VISIBLE);
StringBuilder sb = new StringBuilder();
if (detail.length() >= 15) {
sb.append(detail.substring(0, 14)).append("\n");
if (detail.substring(15).length() >= 15) {
sb.append(detail.substring(15, 29));
} else {
sb.append(detail.substring(15));
}
} else {
sb.append(detail);
}
mPopDetail.setText(sb.toString());
}
//准备开始将view转成bitmap
mPopupView.setDrawingCacheEnabled(true);
mPopupView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
mPopupView.layout(0, 0, mPopupView.getMeasuredWidth(), mPopupView.getMeasuredHeight());
mPopupView.buildDrawingCache();
//转成了bitmap
Bitmap mBitmap = mPopupView.getDrawingCache();
//不过我们还得将bitmap转成drawable,drawAt方法参数不能直接用bitmap
Drawable d = new BitmapDrawable(mBitmap);
//这里很重要哦,我们在这里设定气泡显示的位置,不然的话气泡显示不出来,方法是将气泡左偏移一半,上偏移图标的高度
d.setBounds(-mBitmap.getWidth() / 2, -mBitmap.getHeight() - mIconHeight, mBitmap.getWidth() / 2, -mIconHeight);
mOverlayItem = new OverlayItem(item.getPoint(), "", "");
mOverlayItem.setMarker(d);
//调用populate()方法气泡就开始绘制了,可以认为调用了draw
populate();
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean b) {
if (mOverlayItem == null) return;
//将经纬度转换成地图上的坐标
Projection projection = mapView.getProjection();
Point point = projection.toPixels(mOverlayItem.getPoint(), null);
drawAt(canvas, mOverlayItem.getMarker(0), point.x, point.y, false);
}
//每次弹出一个新的气泡时,将前面的消失掉
public void dismiss() {
mOverlayItem = null;
//这句代码很重要,不然的话每个气泡的内容会一样的,因为先前我们将mPopupView进行了cache,现在释放掉才行。
mPopupView.setDrawingCacheEnabled(false);
setLastFocusedIndex(-1);
populate();
}
@Override
protected boolean onTap(int i) {
listener.onPopupViewTap();
return true;
}
public interface PopupViewTapListener {
public void onPopupViewTap();
}
}
3.附上xml布局
map_view.xml
<?xml version="1.0" encoding="utf-8"?>
<com.mapbar.android.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map_view"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:clickable="true"/>
map_popup_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/map_overlay_item_bg"
android:paddingLeft="8dp"
android:paddingRight="8dp"
>
<TextView
android:id="@+id/tv_popup_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:textSize="16sp"
android:textColor="@color/text_color_regular"
/>
<LinearLayout
android:id="@+id/ll_popup_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
>
</LinearLayout>
<TextView
android:id="@+id/tv_popup_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:paddingBottom="8dp"
android:textSize="14sp"
android:textColor="@color/text_color_light"
/>
</LinearLayout>
图片就不贴了,map_overlay_item_bg就是气泡背景图,.9.png格式的。
有问题大家可以交流交流,不知道谁有更好点的方法。
这篇文章讲的是如何自定义一个弹出框,里面包含图片、文字等等,思路是这样的:
我们写一个弹出框的xml布局文件,需要弹出的时候,将这个view转换成bitmap,然后转换成drawable,然后就可以控制这个drawable的位置,比如让它显示在图标的上方,当然可以随意设定弹出的位置。
我们先看看效果图:
地图使用的是图吧的地图,实际上Google Maps也是一样的,API调用方法都一样的,只是图吧地图xml布局里面不需要key。
上图中弹出的气泡时间上是一个LinearLayout,只是将其转换成了drawable,以便使用canvas绘制。
这里我们分成两个部分讲,分成两个类,MapPopupActivity(地图页面)和MapPopupView(弹出框)。
1.首先,我们准备好地图,在此地图上我们将绘制一系列图标,点击图标时弹出气泡。内容有点多,我会进行注释。
MapPopupActivity.java
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import com.mapbar.android.maps.*;
import com.tuan800.credit.R;
import com.tuan800.credit.views.MapPopupView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: chenjishi
* Date: 12-4-10
* Time: 下午4:29
* To change this template use File | Settings | File Templates.
*/
public class MapPopupActivity extends MapActivity implements MapPopupView.PopupViewTapListener {
private List<Spot> mSpotList;
private MapView mMapView;
private MapController mMapController;
private List<Overlay> mOverlayList;
private OverItemT mOverItemT;
//弹出窗口类
private MapPopupView mMapPopupView;
//设定一个地图中心位置
private double mLat = 39.973860D;
private double mLng = 116.382240D;
private Resources mRes;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.map_view);
mMapView = (MapView) this.findViewById(R.id.map_view);
mMapView.setBuiltInZoomControls(true);
mMapController = mMapView.getController();
mMapController.setZoom(12);
mRes = getResources();
//默认图标
Drawable defaultIcon = mRes.getDrawable(R.drawable.my_location);
defaultIcon.setBounds(0, 0, defaultIcon.getIntrinsicWidth(), defaultIcon.getIntrinsicHeight());
//绘制图标的内部类
mOverItemT = new OverItemT(defaultIcon);
//初始化弹出窗
mMapPopupView = new MapPopupView(this, mRes.getDrawable(R.drawable.category_1));
//处理弹出窗的点击事件
mMapPopupView.setPopupViewListener(this);
mOverlayList = mMapView.getOverlays();
//下面这两句很重要,不然图标无法显示
mOverlayList.add(mOverItemT);
mOverlayList.add(mMapPopupView);
//设置地图中心点
setMyLocation();
//初始化一系列图标
setData();
//往地图上绘制图标
setMarkers();
}
private void setMyLocation() {
GeoPoint p = new GeoPoint((int) (mLat * 1E6), (int) (mLng * 1E6));
mOverItemT.addOverlay(new OverlayItem(p, "我的位置", ""), 0);
mMapController.setCenter(p);
}
private void setMarkers() {
if (mSpotList.size() == 0) {
return;
}
for (Spot spot : mSpotList) {
GeoPoint point = new GeoPoint((int) (spot.lat * 1E6), (int) (spot.lng * 1E6));
OverlayItem item = new OverlayItem(point, spot.title, spot.detail);
mOverItemT.addOverlay(item, spot.categoryId);
}
}
@Override
public void onPopupViewTap() {
//点击弹窗时让其消失
mMapPopupView.dismiss();
}
//内部类,负责图标的绘制
class OverItemT extends ItemizedOverlay<OverlayItem> {
//每一个OverlayItem就是一个图标
ArrayList<OverlayItem> itemList = new ArrayList<OverlayItem>();
public OverItemT(Drawable drawable) {
super(boundCenterBottom(drawable));
}
public void addOverlay(OverlayItem item, int idx) {
if (item == null) return;
//这里我们根据spot的id分配不同的图标
Drawable icon;
int iconIdx = R.drawable.my_location;
if (idx >= 1 && idx <= 4) {
iconIdx = mRes.getIdentifier("drawable/category_" + idx, null, getPackageName());
}
icon = mRes.getDrawable(iconIdx);
item.setMarker(icon);
boundCenterBottom(icon);
itemList.add(item);
populate();
}
@Override
protected OverlayItem createItem(int i) {
return itemList.get(i);
}
@Override
public int size() {
return itemList.size();
}
//这里负责图标点击事件,如果点击的是当前位置,不弹窗,当前位置i=0,每一次点击时,我们将其他的弹窗关掉,本类中只存在一个弹窗类对象。
@Override
protected boolean onTap(int i) {
mMapPopupView.dismiss();
if (i == 0) return true;
OverlayItem item = itemList.get(i);
setFocus(item);
//int数组2,3是弹窗图标索引,这里我们将在弹窗里面绘制两个图标
mMapPopupView.addOverlay(item, new int[]{2, 3});
mMapController.animateTo(item.getPoint());
return true;
}
//这里是点击图标之外的区域,让已经显示的弹窗消失。
@Override
public boolean onTap(GeoPoint geoPoint, MapView mapView) {
if (!super.onTap(geoPoint, mapView)) {
mMapPopupView.dismiss();
}
return true;
}
//super.draw(canvas, mapView, false);false代表不绘制阴影
@Override
public void draw(Canvas canvas, MapView mapView, boolean b) {
super.draw(canvas, mapView, false);
}
}
private void setData() {
mSpotList = new ArrayList<Spot>();
String[] names = {
"宏状元粥店(健德门店)",
"非尝羊蝎子(马甸店)",
"非尝羊蝎子婆婆鱼",
"天丽姿美容(双安店",
"牛魔王拉面(健德门店)",
"福美炫彩电玩台球俱乐部",
"福美炫彩电玩城",
"华乐文化艺术培训中心(马甸校区)",
"清香阁(健德门桥店)",
"芭斯罗缤(北辰世纪店)",
"北京雅谛思艺术培训",
"食尚芭萨西饼屋",
"清香阁(健德门桥店)",
"非尝羊蝎子婆婆鱼"
};
String[] lats = {
"39.973831",
"39.97335",
"39.97625",
"39.975761",
"39.976719",
"39.975848",
"39.975761",
"39.976719",
"39.927289",
"39.976719",
"39.97656",
"39.976586",
"39.972751",
"39.977435"
};
String[] lngs = {
"116.381906",
"116.383853",
"116.38121",
"116.379047",
"116.379857",
"116.380286",
"116.379047",
"116.379857",
"116.291042",
"116.379857",
"116.37946",
"116.385382",
"116.386314",
"116.386266"
};
for (int i = 0; i < lngs.length; i++) {
Spot spot = new Spot();
spot.title = names[i];
spot.lat = Double.parseDouble(lats[i]);
spot.lng = Double.parseDouble(lngs[i]);
spot.categoryId = (i % 4) + 1;
spot.detail = "仅售9元,新辣道梭边鱼随你吃!新辣道+拉手网!本单所售全部款项将全部捐给芒果V基金,用于四川凉山贫困儿童救助事业,全国47家店通用,亲,只有抢到了才有机会喔!须为新辣道会员,每桌1名会员即可,如无会员卡,可在门店办理,4月2、3、4、7、8、14、15日拉手券不可使用!锅底需到店另付!";
mSpotList.add(spot);
}
}
private class Spot {
public String title;
public String detail;
public double lat;
public double lng;
public int categoryId;
}
}
2.弹窗类,首先inflat出弹窗内容的view,根据overlayitem的title,detail,设置文字,根据传进来的int数组动态生成图片。
public class MapPopupView extends ItemizedOverlay<OverlayItem> {
OverlayItem mOverlayItem;
Paint mPaint;
//图标的高度,这样我们就可以将气泡偏移这个高度,让气泡放置在图标之上而不遮盖图标
int mIconHeight;
//气泡的xml布局,稍后我们会放在后面贴上
LinearLayout mPopupView;
TextView mPopTitle;
TextView mPopDetail;
LinearLayout mIcons;
Context mContext;
PopupViewTapListener listener;
public MapPopupView(Context context, Drawable drawable) {
super(boundCenterBottom(drawable));
mContext = context;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPopupView = (LinearLayout) inflater.inflate(R.layout.map_popup_view, null);
mPopTitle = (TextView) mPopupView.findViewById(R.id.tv_popup_title);
mPopDetail = (TextView) mPopupView.findViewById(R.id.tv_popup_detail);
mIcons = (LinearLayout) mPopupView.findViewById(R.id.ll_popup_icon);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mIconHeight = drawable.getIntrinsicHeight();
populate();
}
public void setPopupViewListener(PopupViewTapListener listener) {
this.listener = listener;
}
@Override
protected OverlayItem createItem(int i) {
return mOverlayItem;
}
@Override
public int size() {
return mOverlayItem == null ? 0 : 1;
}
public void addOverlay(OverlayItem item, int[] bankIds) {
if (item == null) return;
//设置标题
mPopTitle.setText(item.getTitle());
//生成银行icon
if (bankIds != null && bankIds.length > 0) {
mIcons.setVisibility(View.VISIBLE);
mIcons.removeAllViews();
for (int i : bankIds) {
int iconIdx = mContext.getResources().getIdentifier("drawable/bank_" + i, null, mContext.getPackageName());
ImageView iv = new ImageView(mContext);
iv.setImageResource(iconIdx);
mIcons.addView(iv, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
//设置内容,为了防止内容过长,我们让文字这行,显示15个字,两行就够了
String detail = item.getSnippet();
if (!TextUtils.isEmpty(detail)) {
mPopDetail.setVisibility(View.VISIBLE);
StringBuilder sb = new StringBuilder();
if (detail.length() >= 15) {
sb.append(detail.substring(0, 14)).append("\n");
if (detail.substring(15).length() >= 15) {
sb.append(detail.substring(15, 29));
} else {
sb.append(detail.substring(15));
}
} else {
sb.append(detail);
}
mPopDetail.setText(sb.toString());
}
//准备开始将view转成bitmap
mPopupView.setDrawingCacheEnabled(true);
mPopupView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
mPopupView.layout(0, 0, mPopupView.getMeasuredWidth(), mPopupView.getMeasuredHeight());
mPopupView.buildDrawingCache();
//转成了bitmap
Bitmap mBitmap = mPopupView.getDrawingCache();
//不过我们还得将bitmap转成drawable,drawAt方法参数不能直接用bitmap
Drawable d = new BitmapDrawable(mBitmap);
//这里很重要哦,我们在这里设定气泡显示的位置,不然的话气泡显示不出来,方法是将气泡左偏移一半,上偏移图标的高度
d.setBounds(-mBitmap.getWidth() / 2, -mBitmap.getHeight() - mIconHeight, mBitmap.getWidth() / 2, -mIconHeight);
mOverlayItem = new OverlayItem(item.getPoint(), "", "");
mOverlayItem.setMarker(d);
//调用populate()方法气泡就开始绘制了,可以认为调用了draw
populate();
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean b) {
if (mOverlayItem == null) return;
//将经纬度转换成地图上的坐标
Projection projection = mapView.getProjection();
Point point = projection.toPixels(mOverlayItem.getPoint(), null);
drawAt(canvas, mOverlayItem.getMarker(0), point.x, point.y, false);
}
//每次弹出一个新的气泡时,将前面的消失掉
public void dismiss() {
mOverlayItem = null;
//这句代码很重要,不然的话每个气泡的内容会一样的,因为先前我们将mPopupView进行了cache,现在释放掉才行。
mPopupView.setDrawingCacheEnabled(false);
setLastFocusedIndex(-1);
populate();
}
@Override
protected boolean onTap(int i) {
listener.onPopupViewTap();
return true;
}
public interface PopupViewTapListener {
public void onPopupViewTap();
}
}
3.附上xml布局
map_view.xml
<?xml version="1.0" encoding="utf-8"?>
<com.mapbar.android.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map_view"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:clickable="true"/>
map_popup_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/map_overlay_item_bg"
android:paddingLeft="8dp"
android:paddingRight="8dp"
>
<TextView
android:id="@+id/tv_popup_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:textSize="16sp"
android:textColor="@color/text_color_regular"
/>
<LinearLayout
android:id="@+id/ll_popup_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
>
</LinearLayout>
<TextView
android:id="@+id/tv_popup_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:paddingBottom="8dp"
android:textSize="14sp"
android:textColor="@color/text_color_light"
/>
</LinearLayout>
图片就不贴了,map_overlay_item_bg就是气泡背景图,.9.png格式的。
有问题大家可以交流交流,不知道谁有更好点的方法。
相关文章推荐
- android开发游记:百度地图SDK路线规划和自定义地图UI覆盖物及弹出窗
- Android开发实现popupWindow弹出窗口自定义布局与位置控制方法
- Android Map Api 使用和开发(2) 定位我的位置、地图弹出泡泡、通过经纬度获取地址
- Android开发之自定义可清空内容的EditText
- Android 程式开发:(二十)内容提供者 —— 20.6 自定义ContentProvider的使用
- android开发 - 自定义 弹出 底部菜单
- android开发小技巧(3)dialog自定义弹出框的使用
- Android Map Api 使用和开发(2) 定位我的位置、地图弹出泡泡、通过经纬度获取地址
- (android地图开发) 高德地图自定义标题栏
- Android移动开发-通过自定义算法代码来纠偏地图由GPS定位到的经纬度在地图上显示或解析位置时出现偏移的问题
- (android地图开发) 高德地图自定义对话框
- Android开发技巧之在a标签或TextView控件中单击链接弹出Activity(自定义动作)
- Android Map Api 使用和开发(2) 定位我的位置、地图弹出泡泡、通过经纬度获取地址
- (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
- Android Map Api 使用和开发(2) 定位我的位置、地图弹出泡泡、通过经纬度获取地址
- Android官方开发文档Training系列课程中文版:打印内容之自定义文档打印
- ViewPager嵌套RecycleView(Fragment作为数据源)来展示10条数据,每个Item显示的内容是(Android软件开发工程师)(用自定义的Adapter 实现
- Android Map Api 使用和开发(2) 定位我的位置、地图弹出泡泡、通过经纬度获取地址
- Android Map Api 使用和开发(2) 定位我的位置、地图弹出泡泡、通过经纬度获取地址
- Android Map Api 使用和开发(2) 定位我的位置、地图弹出泡泡、通过经纬度获取地址