代碼我傳到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>

還有泡泡的效果圖 ,很多同學做項目都是時間很緊張的,別人貼出來代碼都覺得不夠直觀,有截圖是王道,

順應大部分懶人的習慣,我編截圖邊發:

2012072620280836  

看到了吧, 泡泡上有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();
    }
}

部分注釋寫在代碼裏了

最後再上一張截圖,在室內通過基站定位到我的位置:

2012072620320233  

五、通過經緯度獲取地址

這個單獨拷貝出來讓大家看看。這個方法獲取地址有時候獲取不到的,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定位,也沒有處理那個是更好的定位的問題。

歡迎大家提建議

 


From:CNBLOGS        
 




創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()