Android Map Api 使用和开发(2) 定位我的位置、地图弹出泡泡、通过经纬度获取地址...

代码我传到csdn资源库了;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定位,也没有处理那个是更好的定位的问题。

欢迎大家提建议

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值