Android百度地图之定位图层

jopen 10年前

使用百度地图结合GPS进行定位一文中,我们已经介绍了利用GPS结合百度地图进行定位,另外我们也可以使用百度SDK里面集成的方法,直接进行定位,这样就不需要我们自己去写GPS定位的方法了,代码原型来自百度Demo,代码如下:

Activity:

package com.home;    import android.app.Activity;  import android.content.Context;    import android.graphics.drawable.Drawable;  import android.os.Bundle;  import android.util.AttributeSet;  import android.util.Log;  import android.view.Menu;  import android.view.MotionEvent;  import android.view.View;  import android.view.View.OnClickListener;  import android.widget.Button;  import android.widget.RadioGroup;  import android.widget.TextView;  import android.widget.Toast;  import android.widget.RadioGroup.OnCheckedChangeListener;    import com.baidu.location.BDLocation;  import com.baidu.location.BDLocationListener;  import com.baidu.location.LocationClient;  import com.baidu.location.LocationClientOption;  import com.baidu.mapapi.map.LocationData;  import com.baidu.mapapi.map.MapController;  import com.baidu.mapapi.map.MapView;  import com.baidu.mapapi.map.MyLocationOverlay;  import com.baidu.mapapi.map.PopupClickListener;  import com.baidu.mapapi.map.PopupOverlay;  import com.baidu.platform.comapi.basestruct.GeoPoint;    /**   * 此demo用来展示如何结合定位SDK实现定位,并使用MyLocationOverlay绘制定位位置 同时展示如何使用自定义图标绘制并点击时弹出泡泡   *    */  public class LocationOverlayActivity extends Activity {     // 定位相关   LocationClient mLocClient;   LocationData locData = null;   public MyLocationListenner myListener = new MyLocationListenner();     // 定位图层   locationOverlay myLocationOverlay = null;   // 弹出泡泡图层   private PopupOverlay pop = null;// 弹出泡泡图层,浏览节点时使用   private TextView popupText = null;// 泡泡view   private View viewCache = null;     // 地图相关,使用继承MapView的MyLocationMapView目的是重写touch事件实现泡泡处理   // 如果不处理touch事件,则无需继承,直接使用MapView即可   MyLocationMapView mMapView = null; // 地图View   private MapController mMapController = null;     // UI相关   OnCheckedChangeListener radioButtonListener = null;   Button requestLocButton = null;   boolean isRequest = false;// 是否手动触发请求定位   boolean isFirstLoc = true;// 是否首次定位     @Override   public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_locationoverlay);    CharSequence titleLable = "定位功能";    setTitle(titleLable);    requestLocButton = (Button) findViewById(R.id.button1);    OnClickListener btnClickListener = new OnClickListener() {       @Override     public void onClick(View v) {      // 手动定位请求      requestLocClick();     }    };    requestLocButton.setOnClickListener(btnClickListener);      RadioGroup group = (RadioGroup) this.findViewById(R.id.radioGroup);    radioButtonListener = new OnCheckedChangeListener() {       @Override     public void onCheckedChanged(RadioGroup group, int checkedId) {      if (checkedId == R.id.defaulticon) {       // 传入null则,恢复默认图标       modifyLocationOverlayIcon(null);      }      if (checkedId == R.id.customicon) {       // 修改为自定义marker       modifyLocationOverlayIcon(getResources().getDrawable(         R.drawable.icon_geo));      }     }    };    group.setOnCheckedChangeListener(radioButtonListener);      // 地图初始化    mMapView = (MyLocationMapView) findViewById(R.id.bmapView);    mMapController = mMapView.getController();    mMapView.getController().setZoom(14);    mMapView.getController().enableClick(true);    mMapView.setBuiltInZoomControls(true);    // 创建 弹出泡泡图层    createPaopao();      // 定位初始化    mLocClient = new LocationClient(this);    locData = new LocationData();    mLocClient.registerLocationListener(myListener);    LocationClientOption option = new LocationClientOption();    option.setOpenGps(true);// 打开gps    option.setCoorType("bd09ll"); // 设置坐标类型    option.setScanSpan(5000);    mLocClient.setLocOption(option);    mLocClient.start();      // 定位图层初始化    myLocationOverlay = new locationOverlay(mMapView);    // 设置定位数据    myLocationOverlay.setData(locData);    // 添加定位图层    mMapView.getOverlays().add(myLocationOverlay);    myLocationOverlay.enableCompass();    // 修改定位数据后刷新图层生效    mMapView.refresh();     }     /**    * 手动触发一次定位请求    */   public void requestLocClick() {    isRequest = true;    mLocClient.requestLocation();    Toast.makeText(LocationOverlayActivity.this, "正在定位……",      Toast.LENGTH_SHORT).show();   }     /**    * 修改位置图标    *     * @param marker    */   public void modifyLocationOverlayIcon(Drawable marker) {    // 当传入marker为null时,使用默认图标绘制    myLocationOverlay.setMarker(marker);    // 修改图层,需要刷新MapView生效    mMapView.refresh();   }     /**    * 创建弹出泡泡图层    */   public void createPaopao() {    viewCache = getLayoutInflater()      .inflate(R.layout.custom_text_view, null);    popupText = (TextView) viewCache.findViewById(R.id.textcache);    // 泡泡点击响应回调    PopupClickListener popListener = new PopupClickListener() {     @Override     public void onClickedPopup(int index) {      Log.v("click", "clickapoapo");     }    };    pop = new PopupOverlay(mMapView, popListener);    MyLocationMapView.pop = pop;   }     /**    * 定位SDK监听函数    */   public class MyLocationListenner implements BDLocationListener {      @Override    public void onReceiveLocation(BDLocation location) {     if (location == null)      return;       locData.latitude = location.getLatitude();     locData.longitude = location.getLongitude();     // 如果不显示定位精度圈,将accuracy赋值为0即可     locData.accuracy = location.getRadius();     locData.direction = location.getDerect();     // 更新定位数据     myLocationOverlay.setData(locData);     // 更新图层数据执行刷新后生效     mMapView.refresh();     // 是手动触发请求或首次定位时,移动到定位点     if (isRequest || isFirstLoc) {      // 移动地图到定位点      mMapController.animateTo(new GeoPoint(        (int) (locData.latitude * 1e6),        (int) (locData.longitude * 1e6)));      isRequest = false;     }     // 首次定位完成     isFirstLoc = false;    }      public void onReceivePoi(BDLocation poiLocation) {     if (poiLocation == null) {      return;     }    }   }     // 继承MyLocationOverlay重写dispatchTap实现点击处理   public class locationOverlay extends MyLocationOverlay {      public locationOverlay(MapView mapView) {     super(mapView);    }      @Override    protected boolean dispatchTap() {     // 处理点击事件,弹出泡泡     popupText.setBackgroundResource(R.drawable.popup);     popupText.setText("我的位置");     pop.showPopup(BMapUtil.getBitmapFromView(popupText), new GeoPoint(       (int) (locData.latitude * 1e6),       (int) (locData.longitude * 1e6)), 8);     return true;    }     }     @Override   protected void onPause() {    mMapView.onPause();    super.onPause();   }     @Override   protected void onResume() {    mMapView.onResume();    super.onResume();   }     @Override   protected void onDestroy() {    // 退出时销毁定位    if (mLocClient != null)     mLocClient.stop();    mMapView.destroy();    super.onDestroy();   }     @Override   protected void onSaveInstanceState(Bundle outState) {    super.onSaveInstanceState(outState);    mMapView.onSaveInstanceState(outState);     }     @Override   protected void onRestoreInstanceState(Bundle savedInstanceState) {    super.onRestoreInstanceState(savedInstanceState);    mMapView.onRestoreInstanceState(savedInstanceState);   }     @Override   public boolean onCreateOptionsMenu(Menu menu) {    return true;   }    }    /**   * 继承MapView重写onTouchEvent实现泡泡处理操作   *    * @author Administrator   *    */  class MyLocationMapView extends MapView {   static PopupOverlay pop = null;// 弹出泡泡图层,点击图标使用     public MyLocationMapView(Context context) {    super(context);   }     public MyLocationMapView(Context context, AttributeSet attrs) {    super(context, attrs);   }     public MyLocationMapView(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);   }     @Override   public boolean onTouchEvent(MotionEvent event) {    if (!super.onTouchEvent(event)) {     // 消隐泡泡     if (pop != null && event.getAction() == MotionEvent.ACTION_UP)      pop.hidePop();    }    return true;   }  }

地图工具类:

package com.home;    import android.graphics.Bitmap;  import android.view.View;    public class BMapUtil {     /**    * 从view 得到图片    *     * @param view    * @return    */   public static Bitmap getBitmapFromView(View view) {    view.destroyDrawingCache();    view.measure(View.MeasureSpec.makeMeasureSpec(0,      View.MeasureSpec.UNSPECIFIED), View.MeasureSpec      .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));    view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());    view.setDrawingCacheEnabled(true);    Bitmap bitmap = view.getDrawingCache(true);    return bitmap;   }  }


配置文件:

<?xml version="1.0" encoding="utf-8"?>  <manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="com.home"      android:versionCode="1"      android:versionName="1.0" >        <uses-sdk          android:minSdkVersion="10"          android:targetSdkVersion="10" />      <!-- 使用网络功能所需权限 -->      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >      </uses-permission>      <uses-permission android:name="android.permission.INTERNET" >      </uses-permission>      <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" >      </uses-permission>      <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" >      </uses-permission>        <!-- 读取手机的当前状态权限,没有的话会报错,这个是使用百度地图API必须的 -->      <uses-permission android:name="android.permission.READ_PHONE_STATE" >      </uses-permission>        <!-- Cache功能需要读写外部存储器 ,若没这个权限,地图加载不出来 -->      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >      </uses-permission>      <!-- 使用GPS需要的权限 -->      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />        <!--               添加屏幕支持        android:anyDensity="true"               这个属性指明应用程序是否包含了能够适用于任何屏幕密度的资源。              对于支持Android1.6(API Level 4)和更高版本的应用程序,这个属性的默认值是true,              并且除非绝对的确认这是应用程序正常工作所必须的,否则不应该把它设置为false。              只是在应用程序直接操作位图时才需要禁止这个属性。                android:largeScreens="true"                这个属性用于指示应用程序是否支持较大外形的屏幕。                一个large类型的屏幕被定义成一个比normal类型的手持设备的屏幕明显还要大的屏幕,                并且为了让应用程序能够良好的使用,使用这个属性时要特别小心,尽管可以依赖系统来调整尺寸,                以便能够填充屏幕。                这个属性的默认值实际上在某些版本之间是不同的,因此最好在任何时候都明确的声明这个属性。                如果设置为false,系统会启用屏幕兼容模式,这时要格外的小心。                android:normalScreens="true"                这个属性用于指示应用程序是否支持普通外形的屏幕。                典型的是HVGA中等密度的屏幕,但是WQVGA低密度和WVGA高密度屏幕也被认为是普通屏幕。                这个属性的默认值是true。                android:smallScreens="true"                 这个属性用于指定应用程序是否支持较小外形的屏幕。                一个small类型的屏幕被定义成一个比normal(传统的HVGA)类型的屏幕还要小的屏幕。                外部服务(如Google Play)不会把不支持小屏的应用程序提供给小屏设备,                因为很少有能够确保该应用程序在小屏幕的设备上正常工作的平台。这个属性的默认值是true。                android:resizeable="true"                 这个属性用于指示针对不同的屏幕尺寸,应用程序是否可以调整尺寸。默认值是true。      -->      <supports-screens          android:anyDensity="true"          android:largeScreens="true"          android:normalScreens="true"          android:resizeable="true"          android:smallScreens="true" />        <application          android:name="com.home.DemoApplication"          android:allowBackup="true"          android:icon="@drawable/ic_launcher"          android:label="@string/app_name"          android:theme="@style/AppTheme" >          <activity              android:name="com.home.LocationOverlayActivity"              android:label="@string/app_name" >              <intent-filter>                  <action android:name="android.intent.action.MAIN" />                    <category android:name="android.intent.category.LAUNCHER" />              </intent-filter>          </activity>            <service              android:name="com.baidu.location.f"              android:enabled="true"              android:process=":remote" >          </service>      </application>    </manifest>

注意:该配置文件与之前的有个区别,多了一个service,它是百度jar包下的一个服务类,这是定位必须要的,不然就不能定位。

Application类同之前一样。

布局文件:

<?xml version="1.0" encoding="utf-8"?>  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent" >        <com.home.MyLocationMapView          android:id="@+id/bmapView"          android:layout_width="fill_parent"          android:layout_height="fill_parent"          android:clickable="true" />        <LinearLayout          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_alignParentRight="true"          android:layout_marginTop="80dip"          android:background="#D000"          android:minWidth="100dip"          android:orientation="vertical"          android:padding="2dp" >            <RadioGroup              android:id="@+id/radioGroup"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:contentDescription="定位icon" >                <RadioButton                  android:id="@+id/defaulticon"                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:checked="true"                  android:text="默认图标" >              </RadioButton>                <RadioButton                  android:id="@+id/customicon"                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:text="自定义图标" >              </RadioButton>          </RadioGroup>      </LinearLayout>        <Button          android:id="@+id/button1"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_alignParentRight="true"          android:layout_alignParentTop="true"          android:layout_marginRight="25dp"          android:layout_marginTop="10dip"          android:background="@drawable/custom_loc" />    </RelativeLayout>

custom_text_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="horizontal" >        <TextView          android:id="@+id/popleft"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:background="@drawable/popup_side"          android:gravity="center"          android:text="更新位置"          android:textColor="#3814ed"          android:textSize="12sp"          android:textStyle="bold" />        <LinearLayout          android:id="@+id/popinfo"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:orientation="vertical" >            <TextView              android:id="@+id/textcache"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:background="@drawable/popup_middle"              android:gravity="center"              android:textColor="@android:color/black"              android:textSize="12sp"              android:textStyle="bold" />            <TextView              android:id="@+id/popdown"              android:layout_width="fill_parent"              android:layout_height="wrap_content"              android:background="@drawable/popup_down"              android:textColor="@android:color/black"              android:textSize="12sp" />      </LinearLayout>        <TextView          android:id="@+id/popright"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:background="@drawable/popup_side"          android:gravity="center"          android:text="更新marker"          android:textColor="#3814ed"          android:textSize="12sp"          android:textStyle="bold" />    </LinearLayout>

附上图片效果:

d8.png

来自:http://blog.csdn.net/u010142437/article/details/11577077