通过百度地图实现仿美团外卖的地图选点确定收货地址

您所在的位置:网站首页 外卖配送范围怎么设置 通过百度地图实现仿美团外卖的地图选点确定收货地址

通过百度地图实现仿美团外卖的地图选点确定收货地址

2023-08-15 03:52| 来源: 网络整理| 查看: 265

转载请标明出处:https://blog.csdn.net/u011133887/article/details/80372616 吐槽自己:好长的标题啊

这个功能想必大家都很熟悉,但是网上搜索到的几篇文章要么是大段的代码看的头晕,要么是不求甚解的复制粘贴,今天我们从布局到实现原理一步步分析,让你也能完成一个仿美团外卖的地址选择页面。

本文项目 GitHub 地址:https://github.com/junerver/BaiduMapDemo 注意:示例项目使用 Kotlin 编写,不了解 Kotlin 的小伙伴可以参考博文中的 Java 代码;

页面布局

首先我们从美团外卖的页面布局开始分析,如下图所示:

布局

可以看出该页面由4个部分组成:1、城市选择;2、地点搜索;3、可拖拽选点的地图空间(我们用百度地图来实现);4、地图选点附近的建筑(POI信息);

城市选择部分我们不做详细分析,因为该处网上有很多示例,注意要使用百度地图的定位sdk获取当前位置城市一次(用于POI搜索)。

地点搜索:如下图所示,点击搜索输入框后并不是打开一个新页面,而是遮挡了地图选点与附近POI信息。

搜索 所以我们的页面布局可以是这样的:

布局分解 UI逻辑:使用一个boolean变量作为标志位,默认为true显示选点布局,false显示搜索布局。 当用户点击搜索框时,隐藏选点布局、显示搜索布局,并将标志位置为false;点击左上角的返回按钮时判断为选点布局直接finish页面,为搜索布局则隐藏搜索布局、显示选点布局(物理返回键逻辑类似);

tip:地图选点中标注当前位置的小红点不是调用百度地图控件生成的,而是直接在一个FrameLayout 中同时放置了一个小红点ImageView与一个百度地图的MapView。

完整的页面代码如下所示:

三个重要概念

实现该功能我们必须要了解以下三个重要的概念、功能(标题可以直接点击进入百度sdk的相关介绍页面):

定位: 这个就不用细说了,进入页面后我们应该首先将MapView显示到用户的当前位置,获取用户的城市信息,处理第一次地理编码获取用户定位位置的POI信息;

地理编码: 当用户拖拽地图View时,我们获取地图中心点的经纬度信息,进行地理编码,并从编码信息的回调接口获取到该位置的POI信息列表,用于展示在MapView下面的列表中;

POI热词建议检索: 当用户在搜索框键入内容时,根据用户当前所在城市或自行选择的城市,发起POI热词建议检索,并将检索结果显示到列表中;

实现步骤

了解了上述的三个重要的概念之后我们可以来整理一下思路开始一步步实现我们的页面了(在文末我会放上GitHub上demo项目的地址)。

1. 实例化上述的三个类,并为之注册监听器 //1、地图、定位相关 mBaiduMap = mMap.getMap(); MapStatus mapStatus = new MapStatus.Builder().zoom(15).build(); MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mapStatus); mBaiduMap.setMapStatus(mMapStatusUpdate); // 地图状态改变相关监听 mBaiduMap.setOnMapStatusChangeListener(this); // 开启定位图层 mBaiduMap.setMyLocationEnabled(true); // 定位图层显示方式 mCurrentMode = MyLocationConfiguration.LocationMode.NORMAL; mBaiduMap.setMyLocationConfigeration(new MyLocationConfiguration(mCurrentMode, true, null)); mLocClient = new LocationClient(this); // 注册定位监听 注意在最新版本中这个方法已经被标注为废弃 mLocClient.registerLocationListener(this); // 定位选项 LocationClientOption option = new LocationClientOption(); /** * coorType - 取值有3个: 返回国测局经纬度坐标系:gcj02 返回百度墨卡托坐标系 :bd09 返回百度经纬度坐标系 * :bd09ll */ option.setCoorType("bd09ll"); // 设置是否需要地址信息,默认为无地址 option.setIsNeedAddress(true); // 设置是否需要返回位置语义化信息,可以在BDLocation.getLocationDescribe()中得到数据,ex:"在天安门附近", // 可以用作地址信息的补充 option.setIsNeedLocationDescribe(true); // 设置是否需要返回位置POI信息,可以在BDLocation.getPoiList()中得到数据 option.setIsNeedLocationPoiList(true); /** * 设置定位模式 Battery_Saving 低功耗模式 Device_Sensors 仅设备(Gps)模式 Hight_Accuracy * 高精度模式 */ option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy); // 设置是否打开gps进行定位 option.setOpenGps(true); // 设置扫描间隔,单位是毫秒 当 parent, View view, int position, long id) { PoiInfo poiInfo = poiInfos.get(position); Logger.d(poiInfo.address + " " + poiInfo.name); //你的业务 setResult(RESULT_OK, intent); finish(); } }); } } 3. POI热词建议检索的 Adapter 与选点附近POI列表的 Adapter /** * POI热词建议检索 */ class PoiSearchAdapter extends BaseAdapter { private Context context; private List list; private ViewHolder holder; public PoiSearchAdapter(Context context, List appGroup) { this.context = context; this.list = appGroup; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int location) { return list.get(location); } @Override public long getItemId(int arg0) { return arg0; } public void addObject(List mAppGroup) { this.list = mAppGroup; notifyDataSetChanged(); } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { holder = new ViewHolder(); convertView = LayoutInflater.from(context).inflate(R.layout.activity_poi_search_item, null); holder.mpoi_name = (TextView) convertView.findViewById(R.id.mpoiNameT); holder.mpoi_address = (TextView) convertView.findViewById(R.id.mpoiAddressT); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.mpoi_name.setText(list.get(position).name); holder.mpoi_address.setText(list.get(position).address); // Log.i("yxx", "==1=poi===城市:" + poiInfo.city + "名字:" + // poiInfo.name + "地址:" + poiInfo.address); return convertView; } public class ViewHolder { public TextView mpoi_name;// 名称 public TextView mpoi_address;// 地址 } } /** * 拖动检索提示 */ class PoiAdapter extends BaseAdapter { private Context context; private List pois; private LinearLayout linearLayout; PoiAdapter(Context context, List pois) { this.context = context; this.pois = pois; } @Override public int getCount() { return pois.size(); } @Override public Object getItem(int position) { return pois.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.locationpois_item, null); linearLayout = (LinearLayout) convertView.findViewById(R.id.locationpois_linearlayout); holder = new ViewHolder(convertView); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } if (position == 0) { holder.iv_gps.setImageDrawable(getResources().getDrawable(R.drawable.gps_orange)); holder.locationpoi_name.setTextColor(Color.parseColor("#FF9D06")); holder.locationpoi_address.setTextColor(Color.parseColor("#FF9D06")); } else { holder.iv_gps.setImageDrawable(getResources().getDrawable(R.drawable.gps_grey)); holder.locationpoi_name.setTextColor(Color.parseColor("#4A4A4A")); holder.locationpoi_address.setTextColor(Color.parseColor("#7b7b7b")); } PoiInfo poiInfo = pois.get(position); holder.locationpoi_name.setText(poiInfo.name); holder.locationpoi_address.setText(poiInfo.address); return convertView; } class ViewHolder { ImageView iv_gps; TextView locationpoi_name; TextView locationpoi_address; ViewHolder(View view) { locationpoi_name = (TextView) view.findViewById(R.id.locationpois_name); locationpoi_address = (TextView) view.findViewById(R.id.locationpois_address); iv_gps = (ImageView) view.findViewById(R.id.iv_gps); } } }

至此我们已经完全的实现了该页面的全部功能,对了,还有几个点击事件,如下所示:

@OnClick({R.id.img_back, R.id.et_jiedao_name,R.id.tv_selected_city}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.img_back: if (!acStateIsMap) { mLlMap.setVisibility(View.VISIBLE); mLlSearch.setVisibility(View.GONE); acStateIsMap = true; } else { this.setResult(Activity.RESULT_CANCELED); finish(); } break; case R.id.et_jiedao_name: if (acStateIsMap) { mLlMap.setVisibility(View.GONE); mLlSearch.setVisibility(View.VISIBLE); acStateIsMap = false; } break; case R.id.tv_selected_city: //手动选择城市 Intent i = new Intent(mContext, ChooseCityActivity.class); i.putExtra("flag", "selectCity"); startActivityForResult(i,REQUEST_CODE_CITY); break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_CITY && resultCode == Activity.RESULT_OK) { //重新选择了城市 mSelectCity = data.getStringExtra("city");//该字段用于POI热词建议检索 mTvSelectedCity.setText(mSelectCity); mSuggestionInfos.clear(); sugAdapter.clear(); sugAdapter.notifyDataSetChanged(); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { if (!acStateIsMap) { mLlMap.setVisibility(View.VISIBLE); mLlSearch.setVisibility(View.GONE); acStateIsMap = true; return false; } else { this.setResult(Activity.RESULT_CANCELED); finish(); return true; } } return super.onKeyDown(keyCode, event); }

至此我们就完整的实现了这个功能了,代码参考了很多网上其他大神的实现,再次表示感谢。我只是对实现逻辑进行了梳理与介绍,想必看完本文后你也已经很明了了每段代码的为什么要这样写了。如果本文对您有一丝微小的帮助,请点赞、喜欢。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3