在上一篇中,记录了实现这个功能时,遇到的一些问题以及解决,那么这篇就看下具体的实现代码.
该功能的思路及问题解决:
主要功能(参照微信发送定位):
- 1.定位所在位置并且展示周边POI(建筑物等信息);
- 2.拖拽地图完成,返回中心覆盖物所处位置周边的POI信息;
- 3.支持关键词等搜索,每次搜索完成,中央覆盖物移动到第一条POI信息的相应位置;
- 4.点击右上角的图标,中央覆盖物回到所定位的位置;
- 5.点击下边列表的某条数据,将中央覆盖物移至该条数据对应的位置;
- 6.发送定位时,有相应的地图位置截图和地址信息.
代码实现:
下面核心代码, 实现功能1和功能2:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ddress);
initLocation();
initListener();
}
private void initLocation() {
// 打开定位图层,显示当前位置
mbaiduMap.setMyLocationEnabled(true);
BitmapDescriptor mapIndicator = BitmapDescriptorFactory.fromResource(R.drawable.map_indicator);
MyLocationConfiguration config = new MyLocationConfiguration(
MyLocationConfiguration.LocationMode.FOLLOWING, //NORMAL普通态 //COMPASS // FOLLOWING跟随态,保持定位图标在地图中心
false, // 是否显示方向
mapIndicator);// 更换图标
mbaiduMap.setMyLocationConfiguration(config);
MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.zoomTo(15);
mbaiduMap.setMapStatus(mapStatusUpdate);
// 创建定位对象
mLocationClient = new LocationClient(this);
// 设置监听器接收结果
mLocationClient.registerLocationListener(new BDAbstractLocationListener() {
@Override // 定位到数据回调此方法
public void onReceiveLocation(BDLocation location) {
isFirstLocation = true;
if (location == null) {
return;
}
if(jobAddress != null){
jobAddress.clear();
}
// 详细的地址信息
mCurrAddrStr = location.getAddrStr();
mCity = location.getCity(); // 城市
mCurrLatitude = location.getLatitude(); // 纬度
mCurrLongitude = location.getLongitude(); // 经度
initSearch();
refreshBaiduMap(mCurrLatitude,mCurrLongitude,radius);
}
});
}
private void refreshBaiduMap(double currLatitude,double currLongitude,float accuracy){
MyLocationData datas = new MyLocationData
.Builder()
.latitude(currLatitude) // 纬度
.longitude(currLongitude) // 经度
.accuracy(accuracy) // 定位的精度
.build();
// 更新我的位置, 刷新界面显示
mbaiduMap.setMyLocationData(datas);
}
@Override
public void initListener() {
mbaiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {
@Override
public void onMapStatusChangeStart(MapStatus mapStatus) {
}
@Override
public void onMapStatusChangeStart(MapStatus mapStatus, int i) {
Log.i("onMapStatusChangeStart,触发的类型 == " + i);
}
@Override
public void onMapStatusChange(MapStatus mapStatus) {
}
@Override
public void onMapStatusChangeFinish(MapStatus mapStatus) {
//定位完成和移动回到原点时会触发
if(isFirstLocation){//是否定位到原点
mapCenterLatLng = mapStatus.target;
getAddressData(mapCenterLatLng);
}
}
});
mbaiduMap.setOnMapTouchListener(new BaiduMap.OnMapTouchListener() {
@Override
public void onTouch(MotionEvent motionEvent) {
switch(motionEvent.getAction()){
case MotionEvent.ACTION_UP:
mapCenterLatLng = mbaiduMap.getMapStatus().target;
//获取周边POI
getAddressData(mapCenterLatLng);
break;
}
}
});
mbaiduMap.setOnMapLoadedCallback(new BaiduMap.OnMapLoadedCallback() {
@Override
public void onMapLoaded() {
//地图加载完成才开始定位
mLocationClient.start();
}
});
}
//获取周边的数据(周围的建筑物)
private void getAddressData(LatLng latlng){
coordinateToAddress(latlng);
}
//逆地理编码(即坐标转地址)
private void coordinateToAddress(LatLng ptCenter){
mSearch = GeoCoder.newInstance();
OnGetGeoCoderResultListener listener = new OnGetGeoCoderResultListener() {
//获取地理编码结果
public void onGetGeoCodeResult(GeoCodeResult result) {
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
//没有检索到结果
}
}
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
//获取反向地理编码结果
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
//没有找到检索结果
}
List<PoiInfo> poiList = result.getPoiList();
PoiInfo poiInfo;
if(isFirstLocation) {//刚进来时,第一条显示当前位置
isFirstLocation = false;
poiInfo = new PoiInfo();
poiInfo.address = result.getAddress();
poiInfo.location = result.getLocation();
poiList.add(0,poiInfo);
}
//设置屏幕下边的ListView数据渲染
setBaseAdater(poiList);
}
};
mSearch.setOnGetGeoCodeResultListener(listener);
mSearch.reverseGeoCode(new ReverseGeoCodeOption()
.location(ptCenter));
}
上面的逻辑点:
- 需求1: 当定位监听registerLocationListener类,监听到定位信息,调用refreshBaiduMap方法显示当前位置坐标,会触发OnMapStatusChangeListener类,从而获取到周边POI;
- 需求2: 当拖拽地图时,触发OnMapTouchListener类,在手势离开屏幕时,拿到地图中心点地理坐标,反地理编码查询周边POI;
实现功能3: 支持关键词等搜索,每次搜索完成,中央覆盖物移动到第一条POI信息的相应位置
public void onClick(View view, int id) {
switch(id){
case R.id.address_search_icon:
if(GlobalUtils.isValidClick(VALID_CLICK)){
search();
}
break;
}
}
private PoiSearch mPoiSearch;
private void initSearch() {
// 创建搜索对象
mPoiSearch = PoiSearch.newInstance();
// 设置监听器
mPoiSearch.setOnGetPoiSearchResultListener(new OnGetPoiSearchResultListener() {
@Override // 接收搜索结果
public void onGetPoiResult(PoiResult poiResult) {
if (poiResult == null || poiResult.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {
if(!GlobalUtils.isOpenGps(Global.getContext())){
showToast(GlobalUtils.getString(R.string.usercenter_selete_address_gps_close));
}else{
if(locationTag){//如果为刚刚进行权限检测后的定位失败,应该为“定位”权限未打开
showNeverAskDialog();
}else {
showToast(GlobalUtils.getString(R.string.usercenter_search_no_result));
}
}
locationTag=false;//复位
return ;
}
setBaseAdater(poiResult.getAllPoi());
}
@Override // 详情数据
public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {
if (poiDetailResult == null || poiDetailResult.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {
showToast(GlobalUtils.getString(R.string.usercenter_search_no_result));
return ;
}
}
@Override
public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {
}
});
//在线搜索
mSuggestionSearch = SuggestionSearch.newInstance();
MyGetSuggResultListener myGetSuggResultListener = new MyGetSuggResultListener(this);
myGetSuggResultListener.setOnGetSuggestionResListener(new OnGetSuggestionResListener() {
@Override
public void getSuggestionRes(List<LocationGpsBean> res) {
//listView渲染数据
setArrayAdater(res);
}
});
mSuggestionSearch.setOnGetSuggestionResultListener(myGetSuggResultListener);
}
//调起搜索的动作
private void search() {
GlobalUtils.hideKeyboard(mEtInputSearch);
String searchInput = mEtInputSearch.getText().toString().trim();
if(TextUtils.isEmpty(searchInput)){
showToast(GlobalUtils.getString(R.string.search_input_content_empty));
return ;
}
//下面做搜寻的操作
if(mPoiSearch == null){
initSearch();
}
// 发起搜索
if(searchInput.contains("市")){
mIsCurrSearchAction = true;
String[] splitInputContent = searchInput.split("市");
int length = splitInputContent.length;
String city= "";
String keyword= "";
if(length==1){ //不能周边搜索,市的名称作为key
keyword = splitInputContent[0];
}
if(length>=2){
city = splitInputContent[0];
keyword = splitInputContent[1];
}
mPoiSearch.searchInCity((new PoiCitySearchOption())
.city(city)
.keyword(keyword));
return;
}
mSuggestionSearch.requestSuggestion((new SuggestionSearchOption())
.city(mCity!=null? mCity:"") //在线搜索 == 关键词搜索
.keyword(searchInput));
}
private List<LocationGpsBean> jobAddress = new ArrayList<>();
//listView渲染数据
private void setBaseAdater(List<PoiInfo> allPoi){
jobAddress.clear();
if(allPoi!=null && allPoi.size()>0) {
if(mIsCurrSearchAction){
MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLng(allPoi.get(0).location);
mbaiduMap.animateMapStatus(mapStatusUpdate);
}
for (PoiInfo info : allPoi) {
LocationGpsBean bean = new LocationGpsBean();
bean.blackName = info.name;
bean.address = (info.address =="") ? info.name : info.address ;
bean.uId = info.uid;
bean.pt = info.location;
jobAddress.add(bean);
}
}else{
showToast(GlobalUtils.getString(R.string.usercenter_search_no_result));
return;
}
mAdapter = new JobAddressAdapter(this, jobAddress);
mLvAddressNews.setAdapter(mAdapter);
mLvAddressNews.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
setSelectP(position);
}
});
mAdapter.selectPosition(0);//默认第1项
selectGpsBean = jobAddress.get(0);
mIsCurrSearchAction = false;
}
实现功能4: 点击右上角的图标,中央覆盖物回到所定位的位置
//点击右上角的图标,中央覆盖物回到所定位的位置;
public void moveToCenter() {
isFirstLocation = true;
//当前定位位置坐标
LatLng latLng = new LatLng(mCurrLatitude, mCurrLongitude);
MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLng(latLng);
mbaiduMap.animateMapStatus(mapStatusUpdate);
}
实现功能5: 点击下边列表的某条数据,将中央覆盖物移至该条数据对应的位置
//listView的事件监听
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
setSelectP(position);
}
});
private void setSelectP(int position){
selectGpsBean = jobAddress.get(position);
mAdapter.selectPosition(position);
mAdapter.notifyDataSetChanged();
mLvAddressNews.smoothScrollToPosition(position);
//将中央覆盖物移至所点击数据对应的位置
MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLng(selectGpsBean.getPt());
mbaiduMap.animateMapStatus(mapStatusUpdate);
}
实现功能6: 发送定位时,有相应的地图位置截图和地址信息
//点击则发送定位
private void onSendAddress(){
LatLng latlng = selectGpsBean.getPt();
loadingDialog.show();
BitmapDescriptor mapCenterPoint = BitmapDescriptorFactory.fromResource(R.drawable.location_origin_point);
OverlayOptions option = new MarkerOptions()
.position(new LatLng(latlng.latitude,latlng.longitude))
.icon(mapCenterPoint);
mbaiduMap.addOverlay(option);
mbaiduMap.setMyLocationEnabled(false);
mIvMapCenter.setVisibility(View.GONE);
//由于图片添加marker需要一定时间,才可以显示,故这里延时500ms
//如果不延时,截图上没有marker
mBaiduMapView.postDelayed(new Runnable() {
@Override
public void run() {
//截图动作
mbaiduMap.snapshot(new BaiduMap.SnapshotReadyCallback() {
@Override
public void onSnapshotReady(Bitmap bitmap)
//上传截图
uploadFile(bitmap);
}
});
}
},500);
}
相应的布局:
<?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"
android:background="@color/color_gray_backgroud">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/layout_base_item_header" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="15dp"
android:background="@drawable/shape_edit_myintroduction"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/address_search_icon"
android:layout_width="36dp"
android:layout_height="36dp"
android:clickable="true"
android:paddingLeft="10dp"
android:paddingRight="6dp"
android:src="@drawable/localbaidu_search" />
<!-- <item name="android:imeOptions">actionSearch</item>-->
<EditText
android:id="@+id/et_address_search_input"
style="@style/EditTextStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@null"
android:hint="搜索"
android:maxLength="20"
android:singleLine="true"
android:textColor="@color/text_gray_01"
android:textSize="@dimen/usercenter_text16_size" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="10dp"
android:background="@color/item_line" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="230dp">
<com.baidu.mapapi.map.MapView
android:id="@+id/mpv_address_baidu"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_map_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/location_origin_point"
android:layout_above="@+id/space_selete_address"
android:layout_centerHorizontal="true"/>
<!--这里设置占位控件space居中,是为了让上面的imageView处于地图屏幕中心偏上一点的位置,不至于和定位的图标重合-->
<Space
android:id="@+id/space_selete_address"
android:layout_height="@dimen/dimen_size_2"
android:layout_width="@dimen/dimen_size_2"
android:layout_centerInParent="true"/>
<Button
android:id="@+id/btn_edit_address_center"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentRight="true"
android:layout_margin="6dp"
android:background="@drawable/icon_gps"
android:onClick="search" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/item_line" />
<!--展示工作地点位置信息的ListView-->
<ListView
android:id="@+id/lv_usercenter_edit_selete_job_address_news"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_white"></ListView>
</LinearLayout>
</RelativeLayout>
说明:上面xml中设置占位控件space居中,是为了让上面的imageView处于地图屏幕中心偏上一点的位置,不至于和定位的图标重合,这样就完成高仿微信发送定位功能.
链接
百度地图开发基础篇
百度地图开发的笔记(篇2)高仿微信发送位置功能