Android仿美团地址选择
最近做了这个功能,分享一下,用的是百度地图api,和美团外卖的地址选择界面差不多,也就是可以搜索或者滑动地图展示地址列表给用户选择,看下效果图先。
文章重点
1、展示地图并定位到“我”的位置
2、滑动地图获取周边poi(逆地理编码)
3、搜索框输入查询poi(POI检索)
前言
这里先提一下,我们要选择的地址信息其实是POI(Point of Interest),即“兴趣点”。在地理信息系统中,一个POI可以是一栋房子、一个景点、一个邮筒或者一个公交站等。
百度地图SDK提供三种类型的POI检索:城市内检索、周边检索和区域检索(即矩形区域检索)。这里我就不详细介绍了,具体请查看百度地图开发文档(http://lbsyun.baidu.com/index.php?title=androidsdk)。
需求分析
我们要实现的功能主要包括两个操作:滑动地图和搜索框搜索。
- 滑动地图:滑动地图主要是获取滑动后地图中心点坐标,然后获取poi信息,但是这里不能用上面提到的三种POI检索方式,POI检索都需要传入关键字(不能为空),而我们仅仅只是滑动地图,所以需要用另外一种方式:逆地理编码检索。使用逆地理编码检索时,可以通过检索结果ReverseGeoCodeResult类的getPoiList()方法获取传入位置周围的POI信息。
- 搜索框搜索:这里就可以使用百度地图SDK提供的三种POI检索方式来进行检索,同时为了方便查看,还可以计算出每个POI和用户之间的距离。
具体实现
一、展示地图并定位到“我”的位置
1.展示地图
展示地图非常简单,首先需要调用SDKInitializer.initialize()方法来进行初始化操作,它接收一个全局的Context参数,记得初始化操作一定要在setContentView()方法前调用(可以到application中进行初始化),然后调用findViewById()方法获取MapView实例,最后记得要对MapView进行资源释放。
2.移动到我的位置
2.1 获取我的位置
首先要确定自己的位置,代码如下所示:
public class MainActivity extends AppCompatActivity implements OnGetPoiSearchResultListener {
private MyLocationListener myListener = new MyLocationListener();
public LocationClient mLocationClient = null;
private LocationClientOption option = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initLocation();
} /**
* 初始化定位相关
*/
private void initLocation() {
// 声明LocationClient类
mLocationClient = new LocationClient(getApplicationContext());
mLocationClient.setLocOption(option);
// 注册监听函数
mLocationClient.registerLocationListener(myListener);
mLocationClient.start();
} /**
* 监听当前位置
*/
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
//mapView 销毁后不在处理新接收的位置
if (location == null || mMapView == null) {
return;
}
if (location.getLocType() == BDLocation.TypeGpsLocation
|| location.getLocType() == BDLocation.TypeNetWorkLocation) {
Log.e(TAG, "当前“我”的位置:" + location.getAddrStr());
navigateTo(location);
}
}
}
}
可以看到,我们首先创建LocationClient实例,然后调用LocationClient的registerLocationListener()方法来注册一个定位监听器,当获取到位置信息的时候,就会回调这个定位监听器。开启定位很简单,只需要调用一下LocationClient的start()方法就可以了。
定位的结果会回调到监听器中,也就是MyLocationListener,在onReceiveLocation()方法中即可通过BDLocation对象获取相关位置详细信息。
注:定位属于危险权限,所以要动态权限申请,记得不要忘记了。
2.2 移动到我的位置
获取到定位后就需要将地图中心点移动到当前位置,代码如下:
private boolean isFirstLocation = true;
/**
* 根据获取到的位置在地图上移动“我”的位置
*
* @param location
*/
private void navigateTo(BDLocation location) {
double longitude = location.getLongitude();
double latitude = location.getLatitude();
if (isFirstLocation) {
currentLatLng = new LatLng(latitude, longitude);
MapStatus.Builder builder = new MapStatus.Builder();
MapStatus mapStatus = builder.target(currentLatLng).zoom(17.0f).build();
mBaiduMap.animateMapStatus(MapStatusUpdateFactory
.newMapStatus(mapStatus));
isFirstLocation = false;
}
//让“我”显示在地图上
MyLocationData.Builder locationBuilder = new MyLocationData.Builder();
locationBuilder.latitude(location.getLatitude());
locationBuilder.longitude(location.getLongitude());
MyLocationData locationData = locationBuilder.build();
mBaiduMap.setMyLocationData(locationData);
}
这里首先将位置信息封装到LatLng对象中,然后调用MapStatusUpdateFactory
的newMapStatus()将LatLng对象传入,接着返回的MapStatusUpdate对象作为参数传入到BaiduMap的animateMapStatus()方法中。上述代码中还使用了一个变量来防止多次调用animateMapStatus()方法,因为移动地图只需要在程序第一次定位时调用一次。
同时为了显示一个当前设备的光标,可以利用MyLocationData.Builder类来实现,如代码所示,就可将“我”显示在地图上了。
二、滑动地图获取poi(逆地理编码)
1. 逆地理编码
前面已经提到了,我们这里滑动地图需要用到逆地理编码,也就是反向地理解析,逆地理编码就是将坐标转换为详细的地址信息,代码如下:
//反向地理解析(含有poi列表)
mGeoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(center)); /**
* 反向地理解析,结果中含有poi信息,用于刚进入地图和移动地图时使用
*/
private void initGeoCoder() {
mGeoCoder = GeoCoder.newInstance();
mGeoCoder.setOnGetGeoCodeResultListener(new OnGetGeoCoderResultListener() {
@Override
public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) { } @Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
if (reverseGeoCodeResult.error.equals(SearchResult.ERRORNO.NO_ERROR)) {
//获取poi列表
if (reverseGeoCodeResult.getPoiList() != null) {
poiInfoListForGeoCoder = reverseGeoCodeResult.getPoiList();
}
} else {
Toast.makeText(mContext, "该位置范围内无信息", Toast.LENGTH_SHORT);
}
}
});
}
这里我们首先获取一个GeoCoder实例,然后注册监听器,当有解析结果时便会回调到onGetReverseGeoCodeResult()方法中,而解析结果便有我们需要的poi列表。反向解析只需要调用GeoCoder的reverseGeoCode()方法并传入移动后地图的中心坐标点即可。
2. 监听地图滑动
百度地图提供了一个地图状态改变的监听器,当双击、滑动、缩放等操作时便进行回调,如下:
mBaiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() { /**
* 手势操作地图,设置地图状态等操作导致地图状态开始改变。
* @param mapStatus 地图状态改变开始时的地图状态
*/
@Override
public void onMapStatusChangeStart(MapStatus mapStatus) {
} /** 因某种操作导致地图状态开始改变。
* @param mapStatus 地图状态改变开始时的地图状态
* @param i 取值有:
* 1:用户手势触发导致的地图状态改变,比如双击、拖拽、滑动底图
* 2:SDK导致的地图状态改变, 比如点击缩放控件、指南针图标
* 3:开发者调用,导致的地图状态改变
*/
@Override
public void onMapStatusChangeStart(MapStatus mapStatus, int i) {
Log.e(TAG, "地图状态改变开始时:" + i + "");
} /**
* 地图状态变化中
* @param mapStatus 当前地图状态
*/
@Override
public void onMapStatusChange(MapStatus mapStatus) {
LatLng latlng = mBaiduMap.getMapStatus().target;
addMarker(latlng);
} /**
* 地图状态改变结束
* @param mapStatus 地图状态改变结束后的地图状态
*/
@Override
public void onMapStatusChangeFinish(MapStatus mapStatus) {
center = mBaiduMap.getMapStatus().target;
//反向地理解析(含有poi列表)
mGeoCoder.reverseGeoCode(new ReverseGeoCodeOption()
.location(center));
}
});
如上,当地图从滑动到结束会回调4个方法,我们需要用到的是:地图状态变化中和地图状态改变结束,也就是对应地图滑动中和滑动结束时。
滑动结束:当滑动结束时便调用反向地理解析出结果,这个上面已经说了。
滑动中:我们会发现当我们滑动地图时,地图上会有一个图标始终处于地图中心,这里就是利用地图状态变化中这个回调来添加一个marker,也就是在地图上添加一个图标,不过这个方法一次滑动可能会回调很多次,但是如果只在滑动结束后添加,用户体验不好,所以如果实在要考虑性能的话可以换个思路,将图标固定在屏幕上大致地图的中心,这样滑动地图看起来也一样的。
添加marker的方法就不详解了,源码里有,一看就懂了。
三、搜索框输入查询poi(POI检索)
搜索框搜索也就是使用关键字检索POI信息,这里不要和Sug检索弄混了,Sug(Suggestion POI search)检索是根据部分关键字检索出可能的完整关键字名称,即关键字匹配。而POI检索是根据关键字检索符合的POI具体信息。
上面说过POI检索有三种方式,这里结合我们的需求来说,使用城市内检索更加合适,也就是传入城市和关键字进行查询,当然你也可以使用另外两种检索方式,步骤如下:
1. 创建POI检索实例
mPoiSearch = PoiSearch.newInstance();
2. 创建POI检索监听器
OnGetPoiSearchResultListener listener = new OnGetPoiSearchResultListener() {
/**
* 获取POI搜索结果
* @param poiResult Poi检索结果,包括城市检索,周边检索,区域检索
*/
@Override
public void onGetPoiResult(PoiResult poiResult) {
if (poiResult.error == SearchResult.ERRORNO.NO_ERROR) {
poiInfoListForSearch = poiResult.getAllPoi();//POI集合
} if (poiResult.error == SearchResult.ERRORNO.AMBIGUOUS_KEYWORD) {
// 当输入关键字在本市没有找到,但在其他城市找到时,返回包含该关键字信息的城市列表
String strInfo = "在";
for (CityInfo cityInfo : poiResult.getSuggestCityList()) {
strInfo += cityInfo.city;
strInfo += ",";
}
strInfo += "找到结果";
Toast.makeText(mContext, strInfo, Toast.LENGTH_LONG).show();
}
}
@Override
public void onGetPoiDetailResult(PoiDetailSearchResult poiDetailSearchResult) { }
@Override
public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) { }
//废弃
@Override
public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) { }
};
3. 设置检索监听器
mPoiSearch.setOnGetPoiSearchResultListener(listener);
4. 发起检索请求
mPoiSearch.searchInCity((new PoiCitySearchOption())
.city(cityName)//城市名称
.keyword(keyword)//必填
.pageCapacity(pageSize)//每页条数
.pageNum(loadIndex));//分页页码
5. 释放检索实例
mPoiSearch.destroy();
为了方便用户查看,我们可以在列表中展示每一个poi和用户之间的距离,利用DistanceUtil类的getDistance()方法传入两个点坐标的LatLng对象即可计算,如下:
double distance=DistanceUtil.getDistance(currentLatLng, latLng);
最后利用EditText的addTextChangedListener监听器监听输入框,如果值改变就进行检索。
至此,整个功能也就做完了,demo里没有做列表分页和动态权限申请,这个常用的你们就自个加咯,最后放下demo地址:
GitHub:https://github.com/yangxch/BaiDuMapSelectDemo
原创不易,转载请注明出处!
Android仿美团地址选择的更多相关文章
- Android 仿美团网,大众点评购买框悬浮效果之修改版
转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17761431),请尊重他人的辛勤劳动成果,谢谢! 我之前写 ...
- Android 仿美团网,探索使用ViewPager+GridView实现左右滑动查看更多分类的功能
看下效果图,自己考虑下自己会如何实现,然后再继续看看作者的实现~ 不记得什么时候,我留意到到美团网首页有使用ViewPager+GridView实现左右滑动查看更多分类的一个功能,感觉它很有趣,于是想 ...
- android仿美团客户端购买框悬浮特效
实现步骤如下: 1,新建一个项目,新建一个MyScrollView继承自ScrollView public class MyScrollView extends ScrollView { ...
- android仿漫画源码、抽奖转盘、Google相册、动画源码等
Android精选源码 android实现仿今日头条的开源项目 波浪效果,实现流量的动态显示 美妆领域的app, 集成了摄像头取色, 朋友圈, 滤镜等 android仿漫画源码 android一个视差 ...
- Android开发:仿美团下拉列表菜单,帮助类,复用简单
近期在项目中须要用到下拉菜单.公司比較推崇美团的下拉菜单,于是要实现该功能.想着.这个功能应该是一个常常会用到的.于是何不写一个帮助类,仅仅要往这个类里面传入特定的參数,既能够实现下来菜单,并且还能够 ...
- Android 仿PhotoShop调色板应用(四) 不同区域颜色选择的颜色生成响应
版权声明:本文为博主原创文章,未经博主允许不得转载. Android 仿PhotoShop调色板应用(四) 不同区域颜色选择的颜色生成响应 上一篇讲过了主体界面的绘制,这里讲解调色板应用中的另外一 ...
- Android动画之仿美团加载数据等待时,小人奔跑进度动画对话框(附顺丰快递员奔跑效果)
Android动画之仿美团加载数据等待时,小人奔跑进度动画对话框(附顺丰快递员奔跑效果) 首句依然是那句老话,你懂得! finddreams :(http://blog.csdn.net/finddr ...
- vue仿淘宝地址选择组件
Vue组件:省市区地址选择组件 <template> <div v-show="addressSelectShow" :style="{'left': ...
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 ...
随机推荐
- Tomcat原理系列之六:详解socket如何封装成request(上)
目录 参与者 总结 @(详解socket如何封装成request) 看源码虽然不能马上提升你的编码水平.但能让你更好的理解编程. 因为我们tomcat多是以NIO形式处理请求,所以本系列讲的都是NIO ...
- 049 模块6-wordcloud库的使用
目录 一.wordcloud库基本介绍 1.1 wordcloud库概述 1.2 wordcloud库的安装 二.wordcloud库使用说明 2.1 wordcloud库基本使用 2.2 wordc ...
- Python的6种运算符(日记)
学习了许久的Python,我单独总结出了Python中比较常见的6种运算符,感觉略有不全,希望大伙可以一起讨论与研究Python! 一.算术运算符 加 减 - 乘 * 除 / 取余 % 取整 // 异 ...
- Java 13 明天发布,最新最全新特性解读
2017年8月,JCP执行委员会提出将Java的发布频率改为每六个月一次,新的发布周期严格遵循时间点,将在每年的3月份和9月份发布. 目前,JDK官网上已经可以看到JDK 13的进展,最新版的JDK ...
- UGUI_游戏界面开发Demo001
1.Alt+Stretch:快速拉伸匹配至画布,与父类大小保持一致. 2.Anchors锚点:实现屏幕自适应 图片也可以实现自适应.Target Graphic (目标图),点击的时候,控件的效果用在 ...
- Kubernetes监控实践
一.Kubernetes介绍 Kubernetes(K8s)是一个开源平台,能够有效简化应用管理.应用部署和应用扩展环节的手动操作流程,让用户更加灵活地部署管理云端应用. 作为可扩展的容错平台,K8s ...
- Servlet实现用户登录
1.登录过程分析: 通过表单收集用户的数据,Servlet通过request对象获得用户提交的数据,服务器还需要从数据库中通过sql语句查询有没有表单提交的数据中的用户.有则登录成功,否则,登录失败. ...
- Docker学习之volume
提供独立于容器之外的持久化存储 容器中的数据会随着容器的消失而消失,为了解决这个问题,产生了数据卷volume. 例子,比如说mysql容器,msyql中的数据应该是持久化的,故应该存储在volume ...
- C++基础之适配器
什么是容器适配器? ”适配器是使一种事物的行为类似于另外一种事物行为的一种机制”,适配器对容器进行包装,使其表现出另外一种行为.例如,stack<int, vector<int> & ...
- Django-中间件-csrf扩展请求伪造拦截中间件-Django Auth模块使用-效仿 django 中间件配置实现功能插拔式效果-09
目录 昨日补充:将自己写的 login_auth 装饰装在 CBV 上 django 中间件 django 请求生命周期 ***** 默认中间件及其大概方法组成 中间件的执行顺序 自定义中间件探究不同 ...