高仿百度外卖地址添加功能(百度地图拖动定位,poi搜索,设置配送范围)

Android开发实战 专栏收录该内容
1 篇文章 0 订阅

今天给大家带来一个百度地图的综合案例,主要是仿百度外卖地址添加功能,主要涉及到的功能有以下几点:

  • 百度地图状态改变监听,用户拖动地图可以实时展示周围的poi信息
  • 打开页面定位用户的位置
  • poi搜索,根据用户搜索的关键字显示poi信息
  • 在地图设置配送范围
  • 判断拖动的位置与搜索的地址是否在配送范围内,并给出友好提示

效果图

这里写图片描述 这里写图片描述
这里写图片描述

集成百度地图api

使用百度地图api需要申请密钥,如下网址有详细操作步奏
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/key
配置环境,导入jar包,参考如下网址(jar导入也可直接文章最后demo)
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/buildproject

主页面布局文件

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:fitsSystemWindows="true"
    android:orientation="vertical" >

    <RelativeLayout
        android:id="@+id/rl_search"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:background="@color/bg_feedback" >

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="30dp"
            android:layout_centerInParent="true"
            android:layout_marginLeft="6dp"
            android:layout_marginRight="12dp"
            android:layout_marginTop="6dp"
            android:layout_toRightOf="@+id/iv_left"
            android:background="@color/bg_mine" >

            <ImageView
                android:id="@+id/iv_search"
                android:layout_width="26dp"
                android:layout_height="26dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="6dp"
                android:paddingRight="6dp" />

            <EditText
                android:id="@+id/et_search"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_toRightOf="@+id/iv_search"
                android:background="@color/bg_mine"
                android:gravity="center_vertical"
                android:hint="查找小区,大厦,学校"
                android:paddingLeft="2dp"
                android:singleLine="true"
                android:textColor="@color/black"
                android:textSize="14sp" />
        </RelativeLayout>

        <ImageView
            android:id="@+id/iv_left"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="6dp"
            android:padding="14dp"
            android:src="@drawable/arrow_left" />
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/ll_map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:fitsSystemWindows="true"
        android:orientation="vertical"
        >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="280dp"
        android:orientation="vertical"
        android:visibility="visible" >

        <com.baidu.mapapi.map.MapView
            android:id="@+id/map"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white"
            android:onClick="true" >
        </com.baidu.mapapi.map.MapView>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@color/transparent"
            android:src="@drawable/gps" />
    </RelativeLayout>

    <ListView
        android:id="@+id/lv_near_address"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:cacheColorHint="#00000000"
        android:descendantFocusability="beforeDescendants"
        android:fastScrollEnabled="true"
        android:scrollbars="none" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll_search"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:fitsSystemWindows="true"
        android:orientation="vertical"
        android:visibility="gone">

        <ListView
            android:id="@+id/lv_search"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:cacheColorHint="#00000000"
            android:descendantFocusability="beforeDescendants"
            android:fastScrollEnabled="true"
            android:scrollbars="none" />
    </LinearLayout>

</LinearLayout>
 页面布局主要是MapView+两个listview,其中lv_search是当用户点击搜索框时显示的listview布局,默认隐藏。

主页面功能介绍

参考MainActivity.class

百度地图状态改变监听,用户拖动地图可以实时展示周围的poi信息

       ----------------------------地图状态改变设置----------------------------
        MapStatus mapStatus = new MapStatus.Builder().zoom(15).build();
        MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mapStatus);
        mBaiduMap.setMapStatus(mMapStatusUpdate);
        // 地图状态改变相关监听
        mBaiduMap.setOnMapStatusChangeListener(this);//让MainActivity实现OnMapStatusChangeListener
    ----------------------------反地理编码GeoCoder设置---------------------------
        // 创建GeoCoder实例对象
        geoCoder = GeoCoder.newInstance();
        // 设置查询结果监听者
        geoCoder.setOnGetGeoCodeResultListener(this);//让MainActivity实现OnGetGeoCoderResultListener

    -----------------------MapStatusChange监听回调方法----------------------

    @Override
    public void onMapStatusChangeStart(MapStatus mapStatus) {

    }

    @Override
    public void onMapStatusChange(MapStatus mapStatus) {

    }

    /**
     * 当用户拖动地图结束时,调用该方法
     */
    @Override
    public void onMapStatusChangeFinish(MapStatus mapStatus) {
        // 获取地图最后状态改变的中心点
        LatLng cenpt = mapStatus.target;
        Log.i(TAG, "最后停止点:" + cenpt.latitude+","+cenpt.longitude);
        //判断定位点是否在可配送范围内---如果需要设置配送的范围则加上此段代码
        if (!SpatialRelationUtil.isPolygonContainsPoint(mPoints, cenpt)){
            Toast.makeText(getApplicationContext(),"该地址不在配送范围,请在黄色区域内选择",Toast.LENGTH_LONG).show();
        }
        //将中心点坐标转化为具体位置信息,当转化成功后调用onGetReverseGeoCodeResult()方法
        geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(cenpt));
    }

    -----------------------地理编码监听回调方法----------------------
    @Override
    public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
        //地址转化经纬度
    }
    /**
     * 经纬度转化地址成功后调用
     */
    @Override
    public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
       //经纬度转化地址
        final List<PoiInfo> poiInfos = reverseGeoCodeResult.getPoiList();
        for(int i=0;i<poiInfos.size();i++){
            Log.i(TAG, "这里的值:" + poiInfos.get(i).name);
        }

        if (poiInfos != null && !"".equals(poiInfos)) {
            //创建poiAdapter 将获取到的Poi数据传入,更新UI
            PoiListAdapter poiAdapter = new PoiListAdapter(MainActivity.this, poiInfos);
            lv_near_address.setAdapter(poiAdapter);
            lv_near_address.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    String name = poiInfos.get(position).name.toString();
                    Toast.makeText(getApplicationContext(),name+"---->获取数据返回到添加地址页面",Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

PoiListAdapter .class

package com.junwu.mymapdemo;

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.baidu.mapapi.search.core.PoiInfo;

import java.util.List;

/**
 * Author:JunWu
 * Date:2017/3/1
 * Version:v1.0.0
 * class describe:
 */

public class PoiListAdapter extends BaseAdapter {
    private Context context;
    private List<PoiInfo> pois;
    private LinearLayout linearLayout;

    PoiListAdapter(Context context, List<PoiInfo> 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) {
        PoiListAdapter.ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.pois_list_item, null);
            holder = new PoiListAdapter.ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (PoiListAdapter.ViewHolder) convertView.getTag();
        }
        PoiInfo poiInfo = pois.get(position);
        if (position == 0) {
            holder.iv_gps_icon.setVisibility(View.VISIBLE);
            holder.tv_pois_name.setTextColor(Color.parseColor("#D13600"));
            holder.tv_pois_address.setTextColor(Color.parseColor("#D13600"));
            holder.tv_pois_name.setText("[当前位置]"+poiInfo.name);
            holder.tv_pois_address.setText(poiInfo.address);
        }else{
            holder.iv_gps_icon.setVisibility(View.INVISIBLE);
            holder.tv_pois_name.setTextColor(Color.parseColor("#4A4A4A"));
            holder.tv_pois_address.setTextColor(Color.parseColor("#ffa9a9a9"));
            holder.tv_pois_name.setText(poiInfo.name);
            holder.tv_pois_address.setText(poiInfo.address);
        }

        return convertView;
    }

    class ViewHolder {
        ImageView iv_gps_icon;
        TextView tv_pois_name;
        TextView tv_pois_address;

        ViewHolder(View view) {
            tv_pois_name = (TextView) view.findViewById(R.id.tv_pois_name);
            tv_pois_address = (TextView) view.findViewById(R.id.tv_pois_address);
            iv_gps_icon = (ImageView) view.findViewById(R.id.iv_gps_icon);
        }
    }
}

主要用到百度地图sdk中

  • 开发指南/事件监听/地图事件监听

  • 开发指南/检索功能/地理编码

参考如下链接查找学习。
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/listener#.E5.9C.B0.E5.9B.BE.E4.BA.8B.E4.BB.B6.E7.9B.91.E5.90.AC

http://lbsyun.baidu.com/index.php?title=androidsdk/guide/retrieval#.E5.9C.B0.E7.90.86.E7.BC.96.E7.A0.81

定位用户的位置

参考MainActivity.class

//---------------------------------------百度定位设置------------------------------------//
        // 开启定位图层
        mBaiduMap.setMyLocationEnabled(true);
        // 定位图层显示方式
        mCurrentMode = MyLocationConfiguration.LocationMode.NORMAL;
        mBaiduMap.setMyLocationConfigeration(new MyLocationConfiguration(mCurrentMode, true, null));
        mLocClient = new LocationClient(this);
        // 注册定位监听。让MainActivity实现BDLocationListener,当系统定位成功则调用onReceiveLocation()方法
        mLocClient.registerLocationListener(this);
        // 定位参数选项
        LocationClientOption option = new LocationClientOption();
        option.setCoorType("bd09ll");
        // 设置是否需要地址信息,默认为无地址
        option.setIsNeedAddress(true);
        // 设置是否需要返回位置语义化信息,可以在BDLocation.getLocationDescribe()中得到数据,ex:"在天安门附近",
        // 可以用作地址信息的补充
        option.setIsNeedLocationDescribe(true);
        // 设置是否需要返回位置POI信息,可以在BDLocation.getPoiList()中得到数据
        option.setIsNeedLocationPoiList(true);
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        // 设置是否打开gps进行定位
        option.setOpenGps(true);
        // 设置 LocationClientOption
        mLocClient.setLocOption(option);
        // 开始定位
        mLocClient.start();
    //-----------------------地图地位回调方法----------------------//
    @Override
    public void onReceiveLocation(BDLocation bdLocation) {
        // 如果bdLocation为空或mapView销毁后不再处理新数据接收的位置
        if (bdLocation == null || mBaiduMap == null) {
            return;
        }

        // 定位数据
        MyLocationData data = new MyLocationData.Builder()
                // 定位精度bdLocation.getRadius()
                .accuracy(bdLocation.getRadius())
                // 此处设置开发者获取到的方向信息,顺时针0-360
                .direction(bdLocation.getDirection())
                // 经度
                .latitude(bdLocation.getLatitude())
                // 纬度
                .longitude(bdLocation.getLongitude())
                // 构建
                .build();

        // 设置定位数据
        mBaiduMap.setMyLocationData(data);

       // 根据定位的地点,以动画方式更新地图状态
        LatLng ll = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
            //判断定位点是否在可配送范围内---如果需要设置配送的范围则加上此段代码
        if (!SpatialRelationUtil.isPolygonContainsPoint(mPoints, ll)){
            Toast.makeText(getApplicationContext(),"该地址不在配送范围,请在可选区域内选择",Toast.LENGTH_LONG).show();

          //ll = SpatialRelationUtil.getNearestPointFromLine(mPoints, ll);//获取离配送范围最近的点坐标
        }
        MapStatusUpdate msu = MapStatusUpdateFactory.newLatLngZoom(ll, 18);
        mBaiduMap.animateMapStatus(msu);

        locationLatLng = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
        // 获取城市,待会用于POISearch
        city = bdLocation.getCity();
        // 发起反地理编码请求(经纬度->地址信息)
        ReverseGeoCodeOption reverseGeoCodeOption = new ReverseGeoCodeOption();
        // 设置反地理编码位置坐标
        reverseGeoCodeOption.location(new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude()));
        geoCoder.reverseGeoCode(reverseGeoCodeOption);

        //只需要打开该页面时定位一次即可,定位成功后关闭定位功能
        mLocClient.stop();
        mBaiduMap.setMyLocationEnabled(false);
    }

主要用到百度定位sdk中

  • 开发指南/获取地址

参考如下链接查找学习。
http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/getloc

poi搜索,根据用户搜索的关键字显示poi信息

参考MainActivity.class

        //----------------------------poi搜索模块设置,注册搜索事件监听---------------------------//
        mPoiSearch = PoiSearch.newInstance();
        //让MainActivity实现OnGetPoiSearchResultListener,当系统定位成功则调用onGetPoiResult()方法
        mPoiSearch.setOnGetPoiSearchResultListener(this);

        //----------------------------控件点击事件处理---------------------------//
        iv_left.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!acStateIsMap){
                    ll_map.setVisibility(View.VISIBLE);
                    ll_search.setVisibility(View.GONE);
                    acStateIsMap=true;
                }
            }
        });
        keyWorldsView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (acStateIsMap) {
                    ll_map.setVisibility(View.GONE);
                    ll_search.setVisibility(View.VISIBLE);
                    acStateIsMap = false;
                }
            }
        });
        /**
         * 当输入关键字变化时,动态更新建议列表
         */
        keyWorldsView.addTextChangedListener(new TextWatcher() {
            @Override
            public void afterTextChanged(Editable arg0) {}
            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {}
            @Override
            public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
                //当EditText控件中文字状态发生改变时调用
                if (cs.length() <= 0) {return;}
                //根据关键字搜索poi信息
                mPoiSearch.searchInCity((new PoiCitySearchOption()).city("西安").keyword(cs.toString()));
            }
        });

//-----------------------Poi搜索回调方法----------------------//
    @Override
    public void onGetPoiResult(PoiResult result) {
        Log.i(TAG, "poiListener-----onGetPoiResult");
        //获取POI检索结果
        if (result == null || result.getAllPoi()==null) {
            Toast.makeText(getApplicationContext(),"暂时没有数据",Toast.LENGTH_LONG).show();
            return;
        }

        for (PoiInfo info : result.getAllPoi()) {
            Log.i(TAG, "当前的搜索信息:" + info.name + " " + info.address );
        }

        final List<PoiInfo> poiInfos = result.getAllPoi();
        //创建searchListAdapter ,绑定获取的poi数据并更新UI
        SearchListAdapter searchListAdapter = new SearchListAdapter(MainActivity.this, poiInfos);
        lv_search.setAdapter(searchListAdapter);
        lv_search.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                LatLng latLng = poiInfos.get(position).location;
                String name = poiInfos.get(position).name;
                //判断定位点是否在可配送范围内---如果需要设置配送的范围则加上此段代码
                if (!SpatialRelationUtil.isPolygonContainsPoint(mPoints, latLng)){
                    Toast.makeText(getApplicationContext(),"该地址不在配送范围,请在黄色区域内选择",Toast.LENGTH_LONG).show();
                    ll_map.setVisibility(View.VISIBLE);
                    ll_search.setVisibility(View.GONE);
                    acStateIsMap=true;
                    LatLng pt1 = SpatialRelationUtil.getNearestPointFromLine(mPoints, latLng);
                    geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(pt1));
                }
                Toast.makeText(getApplicationContext(),name+"---->获取数据返回到添加地址页面",Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {}

    @Override
    public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {}

SearchListAdapter.class

package com.junwu.mymapdemo;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.baidu.mapapi.search.core.PoiInfo;

import java.util.List;

import static android.content.ContentValues.TAG;

/**
 * Author:JunWu
 * Date:2017/3/1
 * Version:v1.0.0
 * class describe:
 */

public class SearchListAdapter extends BaseAdapter {
    private Context context;
    private List<PoiInfo> pois;
    private LinearLayout linearLayout;

    SearchListAdapter(Context context, List<PoiInfo> 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) {
        SearchListAdapter.ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.pois_list_item, null);
            holder = new SearchListAdapter.ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (SearchListAdapter.ViewHolder) convertView.getTag();
        }
        Log.i(TAG, "当前的position:" + position);
        PoiInfo poiInfo = pois.get(position);
        holder.tv_pois_name.setText(poiInfo.name);
        holder.tv_pois_address.setText(poiInfo.address);
        return convertView;
    }

    class ViewHolder {
        ImageView iv_gps_icon;
        TextView tv_pois_name;
        TextView tv_pois_address;

        ViewHolder(View view) {
            tv_pois_name = (TextView) view.findViewById(R.id.tv_pois_name);
            tv_pois_address = (TextView) view.findViewById(R.id.tv_pois_address);
            iv_gps_icon = (ImageView) view.findViewById(R.id.iv_gps_icon);
        }
    }
}

主要用到百度定位sdk中

  • 开发指南/搜索功能/POI检索

参考如下链接查找学习。
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/retrieval#POI.E6.A3.80.E7.B4.A2

在地图设置配送范围

参考MainActivity.class

    /**
     * 设置配送的范围
     */
    private void setDeliveryScope() {
        //配送范围的点自行设置
        LatLng  latLng1=new LatLng(34.22898269265894,108.87636764022244);
        LatLng  latLng2=new LatLng(34.225323612679404,108.87819186944901);
        LatLng  latLng3=new LatLng(34.22578857521661,108.88394050365343);
        LatLng  latLng4=new LatLng(34.2297155315396,108.88647470436645);
        mPoints.add(latLng1);
        mPoints.add(latLng2);
        mPoints.add(latLng3);
        mPoints.add(latLng4);
       //构建用户绘制多边形的Option对象,绘制可配送区域
        OverlayOptions polygonOption = new PolygonOptions()
                .points(mPoints)
                .stroke(new Stroke(5, 0xAA00FF00))
                .fillColor(0xAAFFFF00);
       //在地图上添加多边形Option,用于显示
        mBaiduMap.addOverlay(polygonOption);
    }

主要用到百度定位sdk中

  • 开发指南/基础地图/几何图形覆盖物

参考如下链接查找学习。
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/basicmap#.E5.87.A0.E4.BD.95.E5.9B.BE.E5.BD.A2.E8.A6.86.E7.9B.96.E7.89.A9

判断拖动的位置与搜索的地址是否在配送范围内功能
- 开发指南/计算工具/空间关系判断

http://lbsyun.baidu.com/index.php?title=androidsdk/guide/tool#.E7.A9.BA.E9.97.B4.E5.85.B3.E7.B3.BB.E5.88.A4.E6.96.AD

总结

至此所有功能已经完成,完整代码可去下面地址下载。
http://download.csdn.net/detail/jaryjun/9767320

  • 6
    点赞
  • 3
    评论
  • 7
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值