http://blog.csdn.net/totogo2010/article/details/6574858
(全部源码地址:http://download.csdn.net/detail/totogo2010/4335701 )
主要有这么几道菜:
1、在地图上弹出泡泡显示信息,并且能相应泡泡的点击时间
2、自动定位当前位置(也就是我的位置) --添加了 GPS定位和基站定位。
3、获取经纬度对应的接到地址名称
那下面就开始代码把,理论知识能讲多少是多少。
一 、 地图弹出泡泡的制作
1 、overlay_popup.xml 直接把layout放出来
- <?xml version="1.0" encoding="UTF-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="@drawable/bubble_background" android:layout_height="wrap_content"
- android:layout_width="wrap_content" android:id="@+id/map_bubblebtn"
- android:clickable="true" android:focusable="true" android:paddingTop="5dp"
- android:paddingLeft="5dp" android:paddingRight="5dp"
- android:paddingBottom="10dp">
- <LinearLayout android:orientation="vertical" android:id="@+id/popuptext"
- android:layout_width="wrap_content" android:layout_height="wrap_content">
- <TextView android:id="@+id/map_bubbleTitle"
- android:ellipsize="marquee"
- android:textSize="17sp"
- android:textColor="#000000"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- />
- <TextView android:id="@+id/map_bubbleText"
- android:textSize="14sp"
- android:textColor="#000000"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/map_bubbleTitle"
- />
- </LinearLayout>
- <TextView android:layout_toRightOf="@id/popuptext" android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/expander_ic_minimized"
- />
- </RelativeLayout>
还有泡泡的效果图 ,很多同学做项目都是时间很紧张的,别人贴出来代码都觉得不够直观,有截图是王道,
顺应大部分懒人的习惯,我编截图边发:
看到了吧, 泡泡上有title ,有 desc ,还有一个小icon。我把整个layout 设置成:
android:clickable="true" android:focusable="true"
这样这个layout就相当余一个button了,可以点击。
2、那代码怎么实现呢? FzMapActivity里加入下面代码
- private void initPopView(){
- if(null == popView){
- popView = getLayoutInflater().inflate(R.layout.overlay_popup, null);
- mapView.addView(popView, new MapView.LayoutParams(
- MapView.LayoutParams.WRAP_CONTENT,
- MapView.LayoutParams.WRAP_CONTENT, null,
- MapView.LayoutParams.BOTTOM_CENTER));
- popView.setVisibility(View.GONE);
- }
- }
在进入主界面是 初始化一下view。
private View popView;当然这个变量定义也不能少。
3、自定义 itemizedOverlay MyItemizedOverlay
好把,先把代码放出来,光描述怎么写太费劲了。
- package com.android.fzmap.map;
- import java.util.ArrayList;
- import java.util.List;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.drawable.Drawable;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.RelativeLayout;
- import android.widget.TextView;
- import com.android.fzmap.FzMapActivity;
- import com.android.fzmap.R;
- import com.google.android.maps.GeoPoint;
- import com.google.android.maps.ItemizedOverlay;
- import com.google.android.maps.MapController;
- import com.google.android.maps.MapView;
- import com.google.android.maps.OverlayItem;
- import com.google.android.maps.ItemizedOverlay.OnFocusChangeListener;
- @SuppressWarnings("rawtypes")
- public class MyItemizedOverlay extends ItemizedOverlay implements OnFocusChangeListener,OnClickListener{
- private static final String TAG = "MyItemizedOverlay";
- private List<OverlayItem> overlays = new ArrayList<OverlayItem>();
- private FzMapActivity mContext;
- private GeoPoint point = null;
- private String desc = "";
- private String car_title = "";
- private int layout_x = 0; // 用于设置popview 相对某个位置向x轴偏移
- private int layout_y = -30; // 用于设置popview 相对某个位置向x轴偏移
- private MapView mMapView;
- private MapController mMapCtrl;
- private View mPopView;
- private Drawable itemDrawable;
- private Drawable itemSelectDrawable;
- private OverlayItem selectItem;
- private OverlayItem lastItem;
- public void setItemSelectDrawable(Drawable itemSelectDrawable) {
- this.itemSelectDrawable = itemSelectDrawable;
- }
- public MyItemizedOverlay(Drawable defaultMarker) {
- super(boundCenterBottom(defaultMarker));
- }
- public MyItemizedOverlay(Drawable defaultMarker, Context context, MapView mapView, View popView, MapController mapCtrl) {
- super(boundCenterBottom(defaultMarker));
- itemDrawable = defaultMarker;
- itemSelectDrawable = defaultMarker;
- mContext = (FzMapActivity) context;
- setOnFocusChangeListener(this);
- layout_x = itemDrawable.getBounds().centerX();
- layout_y = - itemDrawable.getBounds().height();
- mMapView = mapView;
- mPopView = popView;
- mMapCtrl = mapCtrl;
- }
- @Override
- protected OverlayItem createItem(int i) {
- return overlays.get(i);
- }
- @Override
- public int size() {
- return overlays.size();
- }
- public void addOverlay(OverlayItem item) {
- overlays.add(item);
- populate();
- }
- public void removeOverlay(int location) {
- overlays.remove(location);
- }
- @Override
- public boolean onTap(GeoPoint p, MapView mapView) {
- return super.onTap(p, mapView);
- }
- @Override
- protected boolean onTap(int index) {
- return super.onTap(index);
- }
- @Override
- public void draw(Canvas canvas, MapView mapView, boolean shadow) {
- super.draw(canvas, mapView, shadow);
- }
- @Override
- public void onFocusChanged(ItemizedOverlay overlay, OverlayItem newFocus) {
- Log.d(TAG , "item focus changed!");
- if (null != newFocus) {
- Log.d(TAG , "centerY : " + itemDrawable.getBounds().centerY() + "; centerX :" + itemDrawable.getBounds().centerX());
- Log.d(TAG , " height : " + itemDrawable.getBounds().height());
- MapView.LayoutParams params = (MapView.LayoutParams) mPopView.getLayoutParams();
- params.x = this.layout_x;//Y轴偏移
- params.y = this.layout_y;//Y轴偏移
- point = newFocus.getPoint();
- params.point = point;
- mMapCtrl.animateTo(point);
- TextView title_TextView = (TextView) mPopView.findViewById(R.id.map_bubbleTitle);
- title_TextView.setText(newFocus.getTitle());
- TextView desc_TextView = (TextView) mPopView.findViewById(R.id.map_bubbleText);
- if(null == newFocus.getSnippet() || "".equals(newFocus.getSnippet())){
- desc_TextView.setVisibility(View.GONE);
- }else{
- this.desc = newFocus.getSnippet();
- desc_TextView.setText(this.desc);
- desc_TextView.setVisibility(View.VISIBLE);
- }
- RelativeLayout button = (RelativeLayout) mPopView.findViewById(R.id.map_bubblebtn);
- button.setOnClickListener(this);
- mMapView.updateViewLayout(mPopView, params);
- mPopView.setVisibility(View.VISIBLE);
- selectItem = newFocus;
- }
- }
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- }
- }
- }
主要是继承 OnFocusChangeListener 监听地图层的变化, 为了方便监听button事件也继承了OnClickListener。
下面这方法监听这个层改变的时间,把泡泡弹出来。
public void onFocusChanged(ItemizedOverlay overlay, OverlayItem newFocus) {
Log.d(TAG , "item focus changed!");
if (null != newFocus) {
Log.d(TAG , "centerY : " + itemDrawable.getBounds().centerY() + "; centerX :" + itemDrawable.getBounds().centerX());
Log.d(TAG , " height : " + itemDrawable.getBounds().height());
MapView.LayoutParams params = (MapView.LayoutParams) mPopView.getLayoutParams();
params.x = this.layout_x;//Y轴偏移
params.y = this.layout_y;//Y轴偏移
point = newFocus.getPoint();
params.point = point;
mMapCtrl.animateTo(point);
TextView title_TextView = (TextView) mPopView.findViewById(R.id.map_bubbleTitle);
title_TextView.setText(newFocus.getTitle());
TextView desc_TextView = (TextView) mPopView.findViewById(R.id.map_bubbleText);
if(null == newFocus.getSnippet() || "".equals(newFocus.getSnippet())){
desc_TextView.setVisibility(View.GONE);
}else{
desc = newFocus.getSnippet();
desc_TextView.setText(desc);
desc_TextView.setVisibility(View.VISIBLE);
}
RelativeLayout button = (RelativeLayout) mPopView.findViewById(R.id.map_bubblebtn);
button.setOnClickListener(this);
mMapView.updateViewLayout(mPopView, params);
mPopView.setVisibility(View.VISIBLE);
selectItem = newFocus;
}
}
二、长按地图获取地图位置并弹出泡泡显示信息
它的继承关系 LongPressOverlay extends Overlay implements OnDoubleTapListener
LongPressOverlay这个层主要是用来接收长按事件 和双击地图界面的
- package com.android.fzmap.map;
- import android.os.Handler;
- import android.view.GestureDetector;
- import android.view.GestureDetector.OnDoubleTapListener;
- import android.view.GestureDetector.OnGestureListener;
- import android.view.MotionEvent;
- import com.android.fzmap.FzMapActivity;
- import com.google.android.maps.MapController;
- import com.google.android.maps.MapView;
- import com.google.android.maps.Overlay;
- public class LongPressOverlay extends Overlay implements OnDoubleTapListener,OnGestureListener{
- private FzMapActivity mContext;
- private MapView mMapView;
- private Handler mHandler;
- private MapController mMapCtrl;
- private GestureDetector gestureScanner = new GestureDetector(this);
- private int level = 0;
- public LongPressOverlay(FzMapActivity context, MapView mapView, Handler handler,MapController mapCtrl){
- mContext = context;
- mMapView = mapView;
- mHandler = handler;
- mMapCtrl = mapCtrl;
- }
- @Override
- public boolean onTouchEvent(MotionEvent event, MapView mapView) {
- return gestureScanner.onTouchEvent(event);
- }
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
- return false;
- }
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- return false;
- }
- @Override
- public boolean onDoubleTapEvent(MotionEvent e) {
- if(++level % 3 == 0){
- mMapCtrl.zoomIn();
- level = 0;
- }
- return false;
- }
- @Override
- public boolean onDown(MotionEvent e) {
- return false;
- }
- @Override
- public void onShowPress(MotionEvent e) {
- }
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- return false;
- }
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
- return false;
- }
- @Override
- public void onLongPress(MotionEvent e) {
- mContext.locPoint = mMapView.getProjection().fromPixels((int) e.getX(),
- (int) e.getY());
- mHandler.sendEmptyMessage(mContext.MSG_VIEW_LONGPRESS);
- }
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- return false;
- }
- }
@Override
public void onLongPress(MotionEvent e) {
mContext.locPoint = mMapView.getProjection().fromPixels((int) e.getX(),
(int) e.getY());
mHandler.sendEmptyMessage(mContext.MSG_VIEW_LONGPRESS);
}接收到长按事件后给主界面发消息,由主界面处理。
三、FzLocationManager 这个类用来做gps,基站定位
- package com.android.fzmap.map;
- import android.content.Context;
- import android.location.Location;
- import android.location.LocationListener;
- import android.location.LocationManager;
- import android.os.Bundle;
- import android.util.Log;
- /**
- * @author why
- */
- public class FzLocationManager {
- private final String TAG = "FzLocationManager";
- private static Context mContext;
- private LocationManager gpsLocationManager;
- private LocationManager networkLocationManager;
- private static final int MINTIME = 2000;
- private static final int MININSTANCE = 2;
- private static FzLocationManager instance;
- private Location lastLocation = null;
- private static LocationCallBack mCallback;
- public static void init(Context c , LocationCallBack callback) {
- mContext = c;
- mCallback = callback;
- }
- private FzLocationManager() {
- // Gps 定位
- gpsLocationManager = (LocationManager) mContext
- .getSystemService(Context.LOCATION_SERVICE);
- Location gpsLocation = gpsLocationManager
- .getLastKnownLocation(LocationManager.GPS_PROVIDER);
- gpsLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
- MINTIME, MININSTANCE, locationListener);
- // 基站定位
- networkLocationManager = (LocationManager) mContext
- .getSystemService(Context.LOCATION_SERVICE);
- Location networkLocation = gpsLocationManager
- .getLastKnownLocation(LocationManager.GPS_PROVIDER);
- networkLocationManager.requestLocationUpdates(
- LocationManager.NETWORK_PROVIDER, MINTIME, MININSTANCE,
- locationListener);
- }
- public static FzLocationManager getInstance() {
- if (null == instance) {
- instance = new FzLocationManager();
- }
- return instance;
- }
- private void updateLocation(Location location) {
- lastLocation = location;
- mCallback.onCurrentLocation(location);
- }
- private final LocationListener locationListener = new LocationListener() {
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {
- }
- @Override
- public void onProviderEnabled(String provider) {
- }
- @Override
- public void onProviderDisabled(String provider) {
- }
- @Override
- public void onLocationChanged(Location location) {
- Log.d(TAG, "onLocationChanged");
- updateLocation(location);
- }
- };
- public Location getMyLocation() {
- return lastLocation;
- }
- private static int ENOUGH_LONG = 1000 * 60;
- public interface LocationCallBack{
- /**
- * 当前位置
- * @param location
- */
- void onCurrentLocation(Location location);
- }
- public void destoryLocationManager(){
- Log.d(TAG, "destoryLocationManager");
- gpsLocationManager.removeUpdates(locationListener);
- networkLocationManager.removeUpdates(locationListener);
- }
- }
public interface LocationCallBack{
/**
* 当前位置
* @param location
*/
void onCurrentLocation(Location location);
}
定义一个接口 ,当监听到位置变化时,回调主界面
//locationListener注册监听器到位置服务管理里
networkLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, MINTIME, MININSTANCE,
locationListener);
//位置信息变化回调
private void updateLocation(Location location) {
lastLocation = location;
mCallback.onCurrentLocation(location);
}
四、主界面逻辑
主界面有
- package com.android.fzmap;
- import java.io.IOException;
- import java.util.List;
- import java.util.Locale;
- import android.graphics.drawable.Drawable;
- import android.location.Address;
- import android.location.Geocoder;
- import android.location.Location;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.Window;
- import android.widget.ImageButton;
- import android.widget.TextView;
- import com.android.fzmap.map.FzLocationManager;
- import com.android.fzmap.map.FzLocationManager.LocationCallBack;
- import com.android.fzmap.map.LongPressOverlay;
- import com.android.fzmap.map.MyItemizedOverlay;
- import com.google.android.maps.GeoPoint;
- import com.google.android.maps.MapActivity;
- import com.google.android.maps.MapController;
- import com.google.android.maps.MapView;
- import com.google.android.maps.Overlay;
- import com.google.android.maps.OverlayItem;
- import com.android.fzmap.R;
- public class FzMapActivity extends MapActivity implements LocationCallBack ,OnClickListener{
- /** Called when the activity is first created. */
- private final String TAG = "FzMapActivity";
- private MapView mapView;
- private MapController mMapCtrl;
- private View popView;
- private Drawable myLocationDrawable;
- private Drawable mylongPressDrawable;
- private FzLocationManager fzLocation;
- private MyItemizedOverlay myLocationOverlay;
- private MyItemizedOverlay mLongPressOverlay;
- private List<Overlay> mapOverlays;
- private OverlayItem overlayitem = null;
- public GeoPoint locPoint;
- ImageButton loction_Btn;
- ImageButton layer_Btn;
- ImageButton pointwhat_Btn;
- public final int MSG_VIEW_LONGPRESS = 10001;
- public final int MSG_VIEW_ADDRESSNAME = 10002;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.main);
- loction_Btn = (ImageButton)findViewById(R.id.loction);
- layer_Btn = (ImageButton)findViewById(R.id.layer);
- pointwhat_Btn = (ImageButton)findViewById(R.id.pointwhat);
- loction_Btn.setOnClickListener(this);
- layer_Btn.setOnClickListener(this);
- pointwhat_Btn.setOnClickListener(this);
- myLocationDrawable = getResources().getDrawable(R.drawable.point_where);
- mylongPressDrawable = getResources().getDrawable(R.drawable.point_start);
- mapView = (MapView) findViewById(R.id.map_view);
- mapView.setBuiltInZoomControls(true);
- mapView.setClickable(true);
- initPopView();
- mMapCtrl = mapView.getController();
- myLocationOverlay = new MyItemizedOverlay(myLocationDrawable,this, mapView, popView, mMapCtrl);
- mLongPressOverlay = new MyItemizedOverlay(mylongPressDrawable,this, mapView, popView, mMapCtrl);
- mapOverlays = mapView.getOverlays();
- mapOverlays.add(new LongPressOverlay(this, mapView, mHandler, mMapCtrl));
- //以北京市中心为中心
- GeoPoint cityLocPoint = new GeoPoint(39909230, 116397428);
- mMapCtrl.animateTo(cityLocPoint);
- mMapCtrl.setZoom(12);
- FzLocationManager.init(FzMapActivity.this.getApplicationContext() , FzMapActivity.this);
- fzLocation = FzLocationManager.getInstance();
- }
- private void initPopView(){
- if(null == popView){
- popView = getLayoutInflater().inflate(R.layout.overlay_popup, null);
- mapView.addView(popView, new MapView.LayoutParams(
- MapView.LayoutParams.WRAP_CONTENT,
- MapView.LayoutParams.WRAP_CONTENT, null,
- MapView.LayoutParams.BOTTOM_CENTER));
- popView.setVisibility(View.GONE);
- }
- }
- @Override
- protected boolean isRouteDisplayed() {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public void onCurrentLocation(Location location) {
- Log.d(TAG, "onCurrentLocationy");
- GeoPoint point = new GeoPoint(
- (int) (location.getLatitude() * 1E6),
- (int) (location.getLongitude() * 1E6));
- overlayitem = new OverlayItem(point, "我的位置", "");
- mMapCtrl.setZoom(16);
- if(myLocationOverlay.size() > 0){
- myLocationOverlay.removeOverlay(0);
- }
- myLocationOverlay.addOverlay(overlayitem);
- mapOverlays.add(myLocationOverlay);
- mMapCtrl.animateTo(point);
- }
- private String getLocationAddress(GeoPoint point){
- String add = "";
- Geocoder geoCoder = new Geocoder(getBaseContext(),
- Locale.getDefault());
- try {
- List<Address> addresses = geoCoder.getFromLocation(
- point.getLatitudeE6() / 1E6, point.getLongitudeE6() / 1E6, 1);
- Address address = addresses.get(0);
- int maxLine = address.getMaxAddressLineIndex();
- if(maxLine >= 2){
- add = address.getAddressLine(1) + address.getAddressLine(2);
- }else {
- add = address.getAddressLine(1);
- }
- } catch (IOException e) {
- add = "";
- e.printStackTrace();
- }
- return add;
- }
- Runnable getAddressName = new Runnable() {
- @Override
- public void run() {
- String addressName = "";
- while(true){
- addressName = getLocationAddress(locPoint);
- Log.d(TAG, "获取地址名称");
- if(!"".equals(addressName)){
- break;
- }
- }
- Message msg = new Message();
- msg.what = MSG_VIEW_ADDRESSNAME;
- msg.obj = addressName;
- mHandler.sendMessage(msg);
- }
- };
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_VIEW_LONGPRESS:
- {
- if(null == locPoint) return;
- new Thread(getAddressName).start();
- overlayitem = new OverlayItem(locPoint, "地址名称",
- "正在地址加载...");
- if(mLongPressOverlay.size() > 0){
- mLongPressOverlay.removeOverlay(0);
- }
- popView.setVisibility(View.GONE);
- mLongPressOverlay.addOverlay(overlayitem);
- mLongPressOverlay.setFocus(overlayitem);
- mapOverlays.add(mLongPressOverlay);
- mMapCtrl.animateTo(locPoint);
- mapView.invalidate();
- }
- break;
- case MSG_VIEW_ADDRESSNAME:
- TextView desc = (TextView) popView.findViewById(R.id.map_bubbleText);
- desc.setText((String)msg.obj);
- popView.setVisibility(View.VISIBLE);
- break;
- }
- }
- };
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.loction:
- {
- }
- break;
- default:
- break;
- }
- }
- @Override
- protected void onDestroy() {
- // TODO Auto-generated method stub
- super.onDestroy();
- fzLocation.destoryLocationManager();
- }
- }
部分注释写在代码里了
最后再上一张截图,在室内通过基站定位到我的位置:
五、通过经纬度获取地址
这个单独拷贝出来让大家看看。这个方法获取地址有时候获取不到的,google好像对这个接口有限制。说白了就这这个接口不靠谱。
大家可以尝试用别的方法或手段获取地址
我的代码里加了个死循环去获取位置,这样的方案是不可取的,不过暂时用一下看看效果也好。
/**
* 通过经纬度获取地址
* @param point
* @return
*/
private String getLocationAddress(GeoPoint point){
String add = "";
Geocoder geoCoder = new Geocoder(getBaseContext(),
Locale.getDefault());
try {
List<Address> addresses = geoCoder.getFromLocation(
point.getLatitudeE6() / 1E6, point.getLongitudeE6() / 1E6, 1);
Address address = addresses.get(0);
int maxLine = address.getMaxAddressLineIndex();
if(maxLine >= 2){
add = address.getAddressLine(1) + address.getAddressLine(2);
}else {
add = address.getAddressLine(1);
}
} catch (IOException e) {
add = "";
e.printStackTrace();
}
return add;
}
好了,以上是所有代码, AndroidManifest.xml 在 (一)里有。
最后小结
用google的api获取到的位置放到他的地图上是有偏差的,而且偏差还比不小,大家可以观察一下,这个问题没有很好的免费解决方案。
如果有哪位有什么好建议可以发出来,谢谢。
用基站和gps定位,也没有处理那个是更好的定位的问题。
欢迎大家提建议