最近項目要接入地圖定位,選擇位置的功能,乙方用了百度地圖,記錄一下使用過程。
功能:
可以拖動marker改變定位位置;
點選POI清單對象,mark移動到相應位置;
點選定位回到目前位置。
ps: 搜尋功能暫時沒需要就沒加,也比較簡單。
目錄
一、開發者平台使用
一、申請ak
二、添加相應jar包和so檔案
二、定位代碼實作
一、xml布局
二、recyc
目錄
一、開發者平台使用
一、申請ak
二、添加相應jar包和so檔案
二、定位代碼實作
一、xml布局
二、activity實作
三、recycleadapter
leadapter
三、activity實作
一、開發者平台使用
一、申請ak
注冊個百度地圖開放平台的賬号,建立一個應用 http://lbsyun.baidu.com/
SHA1值的生成,參考這個百度地圖論壇置頂的文章:
http://bbs.lbsyun.baidu.com/forum.php?mod=viewthread&tid=106461&highlight=230
二、添加相應jar包和so檔案
去開發者平台上下載下傳需要的包,複制到AS裡面:
我選了定位,地圖和搜尋的3個包,引入搜尋包是因為,BaiduMap對象的點選事件監聽接口的資料是經緯度對象,
用百度地圖提供的GeoCoder類,可以根據經緯度查找傳回位址,POI,經緯度等資訊。
複制到項目裡面:
把jar包作為項目依賴添加:
File --> Project Structure -->選中app 的dependence,點選 + 号,選中BaiduLBS_Android.jar 包,即可把此jar包添加為項目依賴,上圖裡面jar檔案也出現三角号,可以點開檢視了。
把libs 檔案添加進依賴:
repositories {
flatDir {
dirs 'libs'
}
}
二、定位代碼實作
一、xml布局
<?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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/search_list">
<com.baidu.mapapi.map.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"/>
<! 顯示目前定位位置>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:background="@drawable/bg_location_name"
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:visibility="visible">
<TextView
android:id="@+id/tv_addr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="坐标更新"
android:textColor="@color/white"
android:textSize="14sp"/>
</LinearLayout>
<! 點選回到目前位置>
<LinearLayout
android:id="@+id/my_location"
android:layout_width="30dp"
android:layout_height="30dp"
android:clickable="true"
android:focusable="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="40dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:background="@drawable/bg_location">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/location"/>
</LinearLayout>
</RelativeLayout>
<! 顯示附近POI資訊>
<android.support.v7.widget.RecyclerView
android:id="@+id/search_list"
android:layout_width="match_parent"
android:layout_height="230dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
二、activity實作
我用MVP模式寫的,其實不是标準的mvp,邏輯和資料處理放在presenter裡面了,沒有用model進行資料處理。
1、contract類:
/**
* 百度地圖定位 contract
*/
public interface MapViewContract {
interface View extends BusinessView<Presenter> {
void showAddr(ReverseGeoCodeResult result);
}
abstract class Presenter extends BusinessPresenter<View> {
public Presenter(BusinessActivity activity, View view) {
super(activity, view);
}
//将mapView對象傳過來,用來執行個體化BaiduMap對象
public abstract void getAddr(MapView mMapView);
public abstract void backToCurrentLocation();//回到目前位置
public abstract void setMarkLocation(LatLng latLng);//設定marker位置
}
}
2、activity
/**
* 可拖動 marker 定位
*/
public class MapViewActivity extends BusinessActivity<MapViewContract.Presenter> implements MapViewContract.View, View.OnClickListener, LocationItemAdapter.onItemClickListener {
private MapView mMapView;
private TextView tvAddr;
private String locationAdrr = "";
private LinearLayout myLocation;
private RecyclerView searchListRecycle;
private LocationItemAdapter adapter;
private List<PoiInfo> poiInfoList = new ArrayList<>();
private double longitude;
private double latitude;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_view);
new MapViewPresenter(this, this);
setTitle("選擇位置");
showAheadLayout();
getAheadTextView().setText("确定");
initView();
}
private void initView() {
mMapView = (MapView) findViewById(R.id.mapView);
tvAddr = (TextView) findViewById(R.id.tv_addr);
getPresenter().getAddr(mMapView);
myLocation = (LinearLayout) findViewById(R.id.my_location);
myLocation.setOnClickListener(this);
searchListRecycle = (RecyclerView) findViewById(R.id.search_list);
adapter = new LocationItemAdapter();
adapter.setItemList(poiInfoList);
adapter.setListener(this);
searchListRecycle.setLayoutManager(new LinearLayoutManager(this));
searchListRecycle.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
searchListRecycle.setAdapter(adapter);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.my_location:
//marker回到目前位置
getPresenter().backToCurrentLocation();
break;
}
}
//點選确定,傳回定位的結果
@Override
public void onBarItemClick(ToolBarButton id) {
if (id == ToolBarButton.AHEAD) {
Intent intent = new Intent();
intent.putExtra(KeyName.ADDR_NAME, locationAdrr);
intent.putExtra(KeyName.ADDR_NAME_longitude,longitude);
intent.putExtra(KeyName.ADDR_NAME_latitude,latitude);
setResult(IntentCode.RESULT_ADDR_NAME, intent);
finish();
}
super.onBarItemClick(id);
}
@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mMapView.onPause();
}
@Override
protected void onDestroy() {
mMapView.onDestroy();
mMapView = null;
super.onDestroy();
}
//擷取到定位資訊和周圍POI,傳回結果,view展示資料
@Override
public void showAddr(ReverseGeoCodeResult result) {
tvAddr.setText(result.getAddress());
locationAdrr = result.getAddress();
longitude = result.getLocation().longitude;
latitude = result.getLocation().latitude;
this.poiInfoList = result.getPoiList();
adapter.setItemList(poiInfoList);
adapter.notifyDataSetChanged();
}
//點選POI清單的對象,更新資料,設定marker位置
@Override
public void onItemClick(PoiInfo data, int position) {
if (null != data) {
tvAddr.setText(data.address);
locationAdrr = data.address;
longitude = data.location.longitude;
latitude = data.location.latitude;
getPresenter().setMarkLocation(data.location);
}
}
}
3、presenter類
/**
* 百度地圖定位 presenter
*/
public class MapViewPresenter extends MapViewContract.Presenter implements OnGetGeoCoderResultListener, OnGetPoiSearchResultListener {
private BaiduMap mBaiduMap = null;
private MyLocationData locData; //定位資料包
private Marker marker;//位置标志
boolean isFirstLoc = true; // 是否首次定位
LocationClient mLocClient;
GeoCoder mSearch = null; // 搜尋子產品,根據經緯度擷取位置資訊,也可去掉地圖子產品獨立使用
PoiSearch mPoiSearch;//搜尋附近POI,可用于根據關鍵字搜尋位置
public MapViewPresenter(BusinessActivity activity, MapViewContract.View view) {
super(activity, view);
}
@Override
public void getAddr(MapView mMapView) {
mBaiduMap = mMapView.getMap();
//設定類型
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(18f));
// 開啟定位圖層
mBaiduMap.setMyLocationEnabled(true);
//用application對象初始化LocationClient 對象
mLocClient = new LocationClient(getActivity().getApplicationContext());
//設定位置監聽器
mLocClient.registerLocationListener(listener);
LocationClientOption option = new LocationClientOption();
option.setIsNeedAddress(true);//是否要位址
option.setOpenGps(true);
option.setCoorType("bd09ll"); // 設定坐标類型
//設定定位模式:高精度,低功耗,僅裝置
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
//可選,預設0,即僅定位一次,設定發起連續定位請求的間隔需要大于等于1000ms才是有效的
option.setScanSpan(3000);
mLocClient.setLocOption(option);
mLocClient.start();
//對Marker的點選事件
mBaiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
//擷取marker中的資料
searchNearBy(marker.getPosition());
return false;
}
});
//Map點選事件,點選地圖移動marker
mBaiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng latLng) {
//設定marker位置,将marker移動到點選地圖位置
marker.setPosition(latLng);
//反Geo搜尋,根據經緯度搜尋位置和POI資訊
searchNearBy(marker.getPosition());
}
@Override
public boolean onMapPoiClick(MapPoi mapPoi) {
//同上
marker.setPosition(mapPoi.getPosition());
searchNearBy(marker.getPosition());
return false;
}
});
//對Marker的拖拽事件
mBaiduMap.setOnMarkerDragListener(new BaiduMap.OnMarkerDragListener() {
@Override
public void onMarkerDrag(Marker marker) {
}
@Override
public void onMarkerDragEnd(Marker marker) {
//根據經緯度擷取位置和POI資訊
searchNearBy(marker.getPosition());
}
@Override
public void onMarkerDragStart(Marker marker) {
}
});
// 初始化搜尋子產品,注冊事件監聽
mSearch = GeoCoder.newInstance();
mSearch.setOnGetGeoCodeResultListener(this);
//初始化POI搜尋對象,可根據關鍵字搜尋位址,但是此處我沒有使用它
mPoiSearch = PoiSearch.newInstance();
mPoiSearch.setOnGetPoiSearchResultListener(this);
}
//點選回到目前位置
@Override
public void backToCurrentLocation() {
mLocClient.start();
}
//點選POI清單的item,對應移動marker到相應位置
@Override
public void setMarkLocation(LatLng latLng) {
if (null != marker) {
marker.setPosition(latLng);
MapStatus.Builder builder = new MapStatus.Builder();
builder.target(latLng).zoom(18.0f);
mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
}
}
/***
* 定位結果回調,在此方法中處理定位結果
*/
BDAbstractLocationListener listener = new BDAbstractLocationListener() {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
// map view 銷毀後不在處理新接收的位置
if (mLocClient == null || null == bdLocation) {
return;
}
//構造定位資料
locData = new MyLocationData.Builder()
.accuracy(bdLocation.getRadius())
.latitude(bdLocation.getLatitude())
.longitude(bdLocation.getLongitude())
// 此處設定開發者擷取到的方向資訊,順時針0-360
.direction(100)
.build();
mBaiduMap.setMyLocationData(locData);
LatLng ll = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
MapStatus.Builder builder = new MapStatus.Builder();
builder.target(ll).zoom(18.0f);
//更新地圖狀态
mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
//根據經緯度搜尋位址和POI資訊
searchNearBy(ll);
//隻有第一次定位的時候,構造marker對象
if (isFirstLoc) {
isFirstLoc = false;
BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.mipmap.locationmark);
// 建構MarkerOption,用于在地圖上添加Marker
OverlayOptions option = new MarkerOptions()
.position(ll) //mark出現的位置
.icon(bitmap) //mark圖示
.draggable(true);//mark可拖動
//在地圖上添加Marker并顯示
marker = (Marker) mBaiduMap.addOverlay(option);
} else {
//不是第一次定位,設定marker移動到目前定位的位置
if (null != marker) {
marker.setPosition(ll);
}
}
mLocClient.stop();
}
};
//根據經緯度,用GeoCoder 對象反geo編碼擷取到位置資訊
public void searchNearBy(LatLng latLng) {
if (null != latLng) {
mSearch.reverseGeoCode(new ReverseGeoCodeOption()
.location(latLng));
} else {
ToastUtil.toast("未找到結果");
}
}
//反geo搜尋的 OnGetGeoCodeResultListener傳回資料接口
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
ToastUtil.toast("未能找到結果");
return;
}
getView().showAddr(result);
}
//geo搜尋的 OnGetGeoCodeResultListener傳回資料接口,此處用不到
@Override
public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
}
@Override
public void onDestroy() {
super.onDestroy();
//退出時銷毀定位
mLocClient.stop();
//退出時關閉定位圖層
mBaiduMap.setMyLocationEnabled(false);
mSearch.destroy();
}
/**
* 通過經緯度 和 關鍵字 搜尋poi,此處沒有用到
*
* @param latLng
*/
private void search(LatLng latLng, String name) {
if (null != name) {
mPoiSearch.searchNearby(new PoiNearbySearchOption().keyword(name)
.location(latLng).radius(500).pageNum(1));
} else {
ToastUtil.toast("未找到結果");
//view 的POI清單顯示空
}
}
//mPoiSearch.setOnGetPoiSearchResultListener監聽器傳回資料接口,此處沒用到
//可用于關鍵字搜尋位置資訊和POI資訊
@Override
public void onGetPoiResult(PoiResult poiResult) {
if (poiResult == null || poiResult.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {
ToastUtil.toast("未找到結果");
return;
}
if (poiResult.error == SearchResult.ERRORNO.NO_ERROR) {
ToastUtil.toast("poi 數目:" + poiResult.getAllPoi().size());
return;
}
}
@Override
public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {
}
@Override
public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {
}
}
三、recycleadapter
/**
* 百度地圖定位,顯示POI
*/
public class LocationItemAdapter extends RecyclerView.Adapter<LocationItemAdapter.ViewHolder> implements View.OnClickListener {
private List<PoiInfo> itemList;
private onItemClickListener listener;
private int position;
public void setListener(onItemClickListener listener) {
this.listener = listener;
}
public void setItemList(List<PoiInfo> itemList) {
this.itemList = itemList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_map_location, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.tvName.setText(itemList.get(position).name);
holder.tvAddress.setText(itemList.get(position).address);
holder.itemView.setTag(itemList.get(position));
this.position = position;
holder.rootView.setOnClickListener(this);
}
@Override
public int getItemCount() {
if (null != itemList) {
return itemList.size();
}
return 0;
}
@Override
public void onClick(View v) {
PoiInfo data = (PoiInfo) v.getTag();
if (null != data && null != listener) {
listener.onItemClick(data, position);
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public View rootView;
public TextView tvName;
public TextView tvAddress;
public ViewHolder(View rootView) {
super(rootView);
this.rootView = rootView;
this.tvName = (TextView) rootView.findViewById(R.id.tv_name);
this.tvAddress = (TextView) rootView.findViewById(R.id.tv_address);
}
}
public interface onItemClickListener {
void onItemClick(PoiInfo data, int position);
}
}
注:手勢操作管理
UiSettings settings=mBaiduMap.getUiSettings();
settings.setAllGesturesEnabled(false); //關閉一切手勢操作
settings.setZoomGesturesEnabled(false);//是否允許縮放手勢