Recently, I made this function and shared it with the Baidu Map API, which is similar to the address selection interface of Meituan Takeout. That is, you can search or slide the map to display the address list for users to choose. See the effect picture first.

The article focus on

2. Slide the map to obtain the surrounding POI (reverse geocoding) 3. Enter the search box to query POI (POI search)


preface

It should be noted that the address information we choose is actually a POI (Point of Interest). In gis, a POI can be a house, a scenic spot, a post box, a bus stop, etc. Baidu Map SDK provides three types of POI search: urban search, peripheral search and regional search (i.e. rectangular area search). I won’t detail here, specific please see baidu map development documentation (lbsyun.baidu.com/index.php?t…). .

Demand analysis

The function we want to implement mainly includes two operations: slide map and search box search.

  • Sliding maps: mainly for sliding after the map center coordinates, then get poi information, but it cannot use the above mentioned three poi retrieval way, poi retrieve all need incoming keyword (cannot be empty), and we just slide map, so you need to use a different way: reverse geocoding retrieval. When using reverse geocoding retrieval, POI information around the incoming location can be obtained through the getPoiList() method of the retrieval result ReverseGeoCodeResult class.
  • Search box search: here you can use the three POI search methods provided by Baidu Map SDK to search, and at the same time, to facilitate viewing, you can also calculate the distance between each POI and the user.

The specific implementation

First, show the map and locate the location of “me”

1. Show the map

Show the map is very simple, first of all, you need to call SDKInitializer. The initialize () method for initialization, it receives the Context of a global parameter, Call the findViewById() method to retrieve the MapView instance, and free the MapView.

2. Move to my position

2.1 Get my Location First determine your location, the code is as follows:

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();
    }

    /** * Initializes location related */
    private void initLocation(a) {
        // Declare the LocationClient class
        mLocationClient = new LocationClient(getApplicationContext());
        mLocationClient.setLocOption(option);
        // Register the listener function
        mLocationClient.registerLocationListener(myListener);
        mLocationClient.start();
    }

    /** * listen to the current position */
    public class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            //mapView does not process the newly received location after being destroyed
            if (location == null || mMapView == null) {
                return;
            }
            if (location.getLocType() == BDLocation.TypeGpsLocation
                    || location.getLocType() == BDLocation.TypeNetWorkLocation) {
                Log.e(TAG, "Current position of" I ":"+ location.getAddrStr()); navigateTo(location); }}}}Copy the code

As you can see, we first create the LocationClient instance and then call the registerLocationListener() method of the LocationClient to register a location listener that will be called back when location information is retrieved. Enabling positioning is as simple as calling the Start () method of the LocationClient. The result of the location is called back to the listener, MyLocationListener, and the location details can be obtained from the BDLocation object in the onReceiveLocation() method.

Note: Location is a dangerous permission, so dynamic permission application, remember not to forget.

2.2 Move to my Position After obtaining the location, you need to move the center point of the map to the current position, and the code is as follows:

    private boolean isFirstLocation = true;
    /** * Moves the "me" position on the map based on the obtained position **@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.0 f).build();
            mBaiduMap.animateMapStatus(MapStatusUpdateFactory
                    .newMapStatus(mapStatus));
            isFirstLocation = false;
        }
       // Make "ME" appear on the map
        MyLocationData.Builder locationBuilder = new MyLocationData.Builder();
        locationBuilder.latitude(location.getLatitude());
        locationBuilder.longitude(location.getLongitude());
        MyLocationData locationData = locationBuilder.build();
        mBaiduMap.setMyLocationData(locationData);
    }
Copy the code

The LatLng object is then passed in by a call to MapStatusUpdateFactory’s newMapStatus(), The returned MapStatusUpdate object is then passed as a parameter to the animateMapStatus() method of BaiduMap. A variable is also used in the code above to prevent multiple calls to the animateMapStatus() method, since moving a map only needs to be called once when the program first locates it. Also, to display a cursor for the current device, use the MyLocationData.Builder class to display “ME” on the map, as shown in the code.


2. Slide map to obtain POI (Inverse Geocoding)

1. Reverse geocoding

As mentioned above, we need to use reverse geocoding, also known as reverse geoparsing, to slide the map. Reverse geocoding is to convert coordinates into detailed address information, the code is as follows:

    // Reverse geographic parsing (with POI list)
    mGeoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(center));

    /** * Reverse geographic parsing, resulting in POI information, used when entering the map and moving the map */
    private void initGeoCoder(a) {
        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)) {
                    // Get the LIST of POIs
                    if(reverseGeoCodeResult.getPoiList() ! =null) { poiInfoListForGeoCoder = reverseGeoCodeResult.getPoiList(); }}else {
                    Toast.makeText(mContext, "There is no information in this location.", Toast.LENGTH_SHORT); }}}); }Copy the code

Here we first obtain a GeoCoder instance, then register the listener, when have analytical results will call back to onGetReverseGeoCodeResult () method, and the analytical results have the poi list we need. Reverse parsing simply calls the GeoCoder’s reverseGeoCode() method and passes in the center of the moved map.

2. Listen to the map slide

Baidu Map provides a listener for map state change, which can be called back when double-clicking, sliding, zooming and other operations are performed as follows:

        mBaiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {

            /** * Gestures to manipulate the map, set the map state and other operations cause the map state to change. *@paramMapStatus specifies the mapStatus when the mapStatus change begins
            @Override
            public void onMapStatusChangeStart(MapStatus mapStatus) {}/** The map state began to change due to some operation. *@paramMapStatus indicates the mapStatus when the mapStatus changes@paramThe value of I can be: * 1: map state changes triggered by user gestures, such as double clicking, dragging and sliding the bottom map * 2: map state changes caused by SDK, such as clicking on the zoom control and compass icon * 3: map state changes caused by developer calls */
            @Override
            public void onMapStatusChangeStart(MapStatus mapStatus, int i) {
                Log.e(TAG, "Map state change begins:" + i + "");
            }

            /** * Map state is changing *@paramMapStatus current mapStatus */
            @Override
            public void onMapStatusChange(MapStatus mapStatus) {
                LatLng latlng = mBaiduMap.getMapStatus().target;
                addMarker(latlng);
            }

            /** * Map state changes end *@paramMapStatus indicates the mapStatus after the mapStatus change is complete
            @Override
            public void onMapStatusChangeFinish(MapStatus mapStatus) {
                center = mBaiduMap.getMapStatus().target;
                // Reverse geographic parsing (with POI list)
                mGeoCoder.reverseGeoCode(newReverseGeoCodeOption() .location(center)); }});Copy the code

As mentioned above, the local map will call back four methods from slide to end. What we need to use is: map state change and map state change end, that is, the corresponding map slide and slide end. End of slide: When the slide ends, the reverse understanding is called to precipitate the result, as described above. Slide: We find when we slide map, map will have an icon is always in the center, here is to use the map change of state in the callback to add a marker, which is to add an icon on the map, but this method a sliding may back many times, but if only at the end of the slide to add, the user experience is bad, So if you really want to think about performance, fix the icon in the center of the rough map on the screen so that the map will look the same. The method of adding marker is not explained in detail, there is the source code, a look to understand.


Search box input query POI (POI search)

A search box search is a search for POI information using keywords, not to be confused with Sug search, which is a search for possible full keyword names based on partial keywords, i.e. keyword matches. The POI search is to retrieve specific POI information according to keywords. It has been mentioned above that there are three methods of POI search. Based on our requirements, it is more appropriate to use intra-city search, that is, incoming city and keyword search. Of course, you can also use other two methods of search, the steps are as follows:

1. Create a POI search instance

mPoiSearch = PoiSearch.newInstance();
Copy the code


2. Create a POI search listener

OnGetPoiSearchResultListener listener = new OnGetPoiSearchResultListener() {
    /** * Get POI search results *@paramPoiResult Poi search results, including city search, neighborhood search, and region search */
    @Override
    public void onGetPoiResult(PoiResult poiResult) {
        if (poiResult.error == SearchResult.ERRORNO.NO_ERROR) {
            poiInfoListForSearch = poiResult.getAllPoi();/ / POI collection
        }

        if (poiResult.error == SearchResult.ERRORNO.AMBIGUOUS_KEYWORD) {
            // If the input keyword is not found in the city, but is found in another city, returns the list of cities that contain the keyword information
            String strInfo = "In";
            for (CityInfo cityInfo : poiResult.getSuggestCityList()) {
                strInfo += cityInfo.city;
                strInfo += ",";
            }
            strInfo += "Find the result"; Toast.makeText(mContext, strInfo, Toast.LENGTH_LONG).show(); }}@Override
    public void onGetPoiDetailResult(PoiDetailSearchResult poiDetailSearchResult) {}@Override
    public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {}/ / abandoned
    @Override
    public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {}};Copy the code


3. Set the search listener

mPoiSearch.setOnGetPoiSearchResultListener(listener);
Copy the code


4. Initiate a search request

mPoiSearch.searchInCity((new PoiCitySearchOption())
        .city(cityName)// City name
        .keyword(keyword)/ / required
        .pageCapacity(pageSize)// Number of entries per page
        .pageNum(loadIndex));// Paging page number
Copy the code


5. Release the retrieval instance

mPoiSearch.destroy();
Copy the code


double distance=DistanceUtil.getDistance(currentLatLng, latLng);
Copy the code

Finally, the addTextChangedListener listener in EditText listens for the input box and retrieves it if the value changes.


At this point, the whole function is done,demo did not do list paging and dynamic permission application, this common you add up, finally put down the demo address: GitHub: github.com/yangxch/Bai…