2016-04-09 19 views
2

我正在研究一個小應用程序並已實施Google地圖和位置api。目前,我能夠在地圖上看到我所有的標記,並且羣集工作正常。我可以放大打開的簇並能夠看到標記。我有一個具有不同類型的微調,並且一旦選擇該類型被傳遞給地點搜索字符串。取決於類型的Android集羣管理器圖標

這是我的地圖代碼,包括集羣:

public class MapsActivity extends FragmentActivity implements LocationListener,ClusterManager.OnClusterItemInfoWindowClickListener<MyItem> { 

    GoogleMap mMap; 
    double myLatitude = 0; 
    double myLongitude = 0; 

    HashMap<String, String> mMarker = new HashMap<String, String>(); 
    PlaceJSONParser placeJsonParser = new PlaceJSONParser(); 

    private ClusterManager<MyItem> mClusterManager; 
    protected MyItem clickedClusterItem; 

    String[] placeType; 
    String[] placeTypeName; 
    Spinner spinPlaceType; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_maps); 
     // Obtain the SupportMapFragment and get notified when the map is ready to be used. 
     SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() 
       .findFragmentById(R.id.map); 


     mMap = mapFragment.getMap(); 
     onMapReady(); 

     // Array of place types 
     placeType = getResources().getStringArray(R.array.placeType); 

     // Array of place type names 
     placeTypeName = getResources().getStringArray(R.array.placeTypeName); 

     // Creating an array adapter with an array of Place types 
     // to populate the spinner 
     ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.spinner_item, R.id.textview, placeTypeName); 

     // Getting reference to the Spinner 
     spinPlaceType = (Spinner) findViewById(R.id.spinPlaceType); 

     // Setting adapter on Spinner to set place types 
     spinPlaceType.setAdapter(adapter); 

     spinPlaceType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 
      @Override 
      public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 

       int selectedPosition = spinPlaceType.getSelectedItemPosition(); 
       final String type = placeType[selectedPosition]; 

       StringBuilder sb = new StringBuilder(
         "https://maps.googleapis.com/maps/api/place/nearbysearch/json?"); 
       sb.append("location=" + myLatitude + "," + myLongitude); 
       sb.append("&type=" + type); 
       sb.append("&radius=4000"); 
       sb.append("&key=PLACES_KEY"); 
       // Creating a new non-ui thread task to download Google place json 
       // data 
       PlacesTask placesTask = new PlacesTask(); 

       // Invokes the "doInBackground()" method of the class PlaceTask 
       placesTask.execute(sb.toString()); 

      } 

      @Override 
      public void onNothingSelected(AdapterView<?> parent) { 
       StringBuilder sb = new StringBuilder(
         "https://maps.googleapis.com/maps/api/place/nearbysearch/json?"); 
       sb.append("location=" + myLatitude + "," + myLongitude); 
       sb.append("&type=restaurant"); 
       sb.append("&radius=4000"); 
       sb.append("&key=PLACES_KEY"); 
       // Creating a new non-ui thread task to download Google place json 
       // data 
       PlacesTask placesTask = new PlacesTask(); 

       // Invokes the "doInBackground()" method of the class PlaceTask 
       placesTask.execute(sb.toString()); 
      } 
     }); 


     // Will display next 20 places returned form the next_page_token 
     FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab_more); 
     fab.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       Snackbar.make(view, "Finding you some more places.", Snackbar.LENGTH_LONG) 
         .setAction("Action", null).show(); 

       StringBuilder sb = new StringBuilder(
         "https://maps.googleapis.com/maps/api/place/nearbysearch/json?"); 
       sb.append("pagetoken=" + placeJsonParser.getNext_Page_token()); 
       sb.append("&key=PLACES_KEY"); 
       // Creating a new non-ui thread task to download Google place json 
       // data 

       if (placeJsonParser.getNext_Page_token() == null || placeJsonParser.getNext_Page_token() == ""){ 
        Snackbar.make(view, "No more places left to find.", Snackbar.LENGTH_SHORT) 
          .setAction("Action", null).show(); 
       } 

       PlacesTask placesTask = new PlacesTask(); 

       // Invokes the "doInBackground()" method of the class PlaceTask 
       placesTask.execute(sb.toString()); 
      } 
     }); 

     mMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener() { 
      @Override 
      public void onInfoWindowClick(Marker marker) { 
       Intent detailsIntent = new Intent(getBaseContext(), PlaceDetailsActivity.class); 
       String reference = mMarker.get(marker.getId()); 
       marker.getPosition(); 
       detailsIntent.putExtra("reference", reference); 
       detailsIntent.putExtra("markerLat", myLatitude); 
       detailsIntent.putExtra("markerLong", myLongitude); 
       startActivity(detailsIntent); 
      } 
     }); 

    } 

    public void onMapReady(){ 
     // Enabling MyLocation in Google Map 
     mMap.setMyLocationEnabled(true); 
     mMap.getUiSettings().setCompassEnabled(true); 
     mMap.getUiSettings().setZoomControlsEnabled(true); 

     // Getting LocationManager object from System Service 
     // LOCATION_SERVICE 
     LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); 

     // Creating a criteria object to retrieve provider 
     Criteria criteria = new Criteria(); 

     // Getting the name of the best provider 
     String provider = locationManager.getBestProvider(criteria, true); 

     // Getting Current Location From GPS 
     Location location = locationManager.getLastKnownLocation(provider); 

     // onLocationChanged(location); 
     if (location != null) { 
      onLocationChanged(location); 
     } 
    } 

    /** 
    * A method to download json data from url 
    */ 
    private String downloadUrl(String strUrl) throws IOException { 
     String referer =""; 
     StringBuilder jsonResults = new StringBuilder(); 
     HttpURLConnection conn = null; 
     try { 
      URL url = new URL(strUrl); 

      // Creating an http connection to communicate with url 
      conn = (HttpURLConnection) url.openConnection(); 
      if (referer != null) { 
       conn.setRequestProperty("Referer", referer); 
      } 

      InputStreamReader in = new InputStreamReader(conn.getInputStream()); 

      // Load the results into a StringBuilder 
      int read; 
      char[] buff = new char[1024]; 
      while ((read = in.read(buff)) != -1) { 
       jsonResults.append(buff, 0, read); 
      } 
      // Displays the list of places found in the terminal. 
      Log.i("Data", "Places Found: " + jsonResults); 
     } catch (MalformedURLException e) { 
      Log.i("Google Places Utility", "Error processing Places API URL"); 
      return null; 
     } catch (IOException e) { 
      Log.i("Google Places Utility", "Error connecting to Places API"); 
      return null; 
     } finally { 
      if (conn != null) { 
       conn.disconnect(); 
      } 
     } 
     return jsonResults.toString(); 

    } 


    /** 
    * A class, to download Google Places 
    */ 
    private class PlacesTask extends AsyncTask<String, Integer, String> { 

     String data = null; 

     // Invoked by execute() method of this object 
     @Override 
     protected String doInBackground(String... url) { 
      try { 
       data = downloadUrl(url[0]); 
      } catch (Exception e) { 
       Log.d("Background Task", e.toString()); 
      } 
      return data; 
     } 

     // Executed after the complete execution of doInBackground() method 
     @Override 
     protected void onPostExecute(String result) { 
      ParserTask parserTask = new ParserTask(); 

      // Start parsing the Google places in JSON format 
      // Invokes the "doInBackground()" method of the class ParseTask 
      parserTask.execute(result); 
     } 

    } 

    /** 
    * A class to parse the Google Places in JSON format 
    */ 
    private class ParserTask extends 
      AsyncTask<String, Integer, List<HashMap<String, String>>> { 

     JSONObject jObject; 

     // Invoked by execute() method of this object 
     @Override 
     protected List<HashMap<String, String>> doInBackground(
       String... jsonData) { 

      List<HashMap<String, String>> places = null; 

      try { 
       jObject = new JSONObject(jsonData[0]); 

       /** Getting the parsed data as a List construct */ 
       places = placeJsonParser.parse(jObject); 

      } catch (Exception e) { 
       Log.d("Exception", e.toString()); 
      } 
      return places; 
     } 

     // Executed after the complete execution of doInBackground() method 
     @Override 
     protected void onPostExecute(List<HashMap<String, String>> list) { 

      // Clears all the existing markers 
      mMap.clear(); 
      setUpClusterer(list); 

     } 
    } 

    private void setUpClusterer(List<HashMap<String, String>> list) { 

     // Position the map. 
     mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(myLatitude,myLongitude), 13)); 

     // Initialize the manager with the context and the map. 
     // (Activity extends context, so we can pass 'this' in the constructor.) 
     mClusterManager = new ClusterManager<MyItem>(this, mMap); 

     // Point the map's listeners at the listeners implemented by the cluster 
     // manager. 
     mMap.setOnCameraChangeListener(mClusterManager); 
     mMap.setOnMarkerClickListener(mClusterManager); 

     mMap.setInfoWindowAdapter(mClusterManager.getMarkerManager()); 

     mMap.setOnInfoWindowClickListener(mClusterManager); 
     mClusterManager.setOnClusterItemInfoWindowClickListener(this); 

     mClusterManager 
       .setOnClusterItemClickListener(new ClusterManager.OnClusterItemClickListener<MyItem>() { 
        @Override 
        public boolean onClusterItemClick(MyItem item) { 
         clickedClusterItem = item; 
         return false; 
        } 
       }); 
     // Add cluster items (markers) to the cluster manager. 
     addItems(list); 

     mClusterManager.getMarkerCollection().setOnInfoWindowAdapter(
       new MyCustomAdapterForItems()); 
    } 

    public class MyCustomAdapterForItems implements GoogleMap.InfoWindowAdapter { 

     private final View myContentsView; 

     MyCustomAdapterForItems() { 
      myContentsView = getLayoutInflater().inflate(
        R.layout.info_window, null); 
     } 
     @Override 
     public View getInfoWindow(Marker marker) { 

      TextView tvTitle = ((TextView) myContentsView 
        .findViewById(R.id.txtTitle)); 
      TextView tvSnippet = ((TextView) myContentsView 
        .findViewById(R.id.txtSnippet)); 

      tvTitle.setText(clickedClusterItem.getTitle()); 
      tvSnippet.setText(clickedClusterItem.getSnippet()); 

      return myContentsView; 
     } 

     @Override 
     public View getInfoContents(Marker marker) { 
      return null; 
     } 
    } 

    private void addItems(List<HashMap<String, String>> list) { 
     double latitude; 
     double longitude; 

     for (int i = 0; i < list.size(); i++) { 
      HashMap<String, String> hmPlace = list.get(i); 

      // Getting latitude of the place 
      latitude = Double.parseDouble(hmPlace.get("lat")); 

      // Getting longitude of the place 
      longitude = Double.parseDouble(hmPlace.get("lng")); 

      String name = hmPlace.get("place_name"); 

      // Getting vicinity 
      String vicinity = hmPlace.get("vicinity"); 
      MyItem offsetItem = new MyItem(latitude, longitude, hmPlace.get("reference"), name, vicinity); 
      mClusterManager.addItem(offsetItem); 

     } 
    } 

    public void onClusterItemInfoWindowClick(MyItem item) { 
     Intent placesIntent = new Intent(getBaseContext(), PlaceDetailsActivity.class); 
     String reference = item.getReference(); 

     placesIntent.putExtra("name", item.getTitle()); 
     placesIntent.putExtra("reference", reference); 
     placesIntent.putExtra("sourcelat", myLatitude); 
     placesIntent.putExtra("sourcelng", myLongitude); 
     startActivity(placesIntent); 
    } 

    @Override 
    public void onLocationChanged(Location location) { 
     myLatitude = location.getLatitude(); 
     myLongitude = location.getLongitude(); 
     LatLng myLocation = new LatLng(myLatitude, myLongitude); 
     mMap.moveCamera(CameraUpdateFactory.newLatLng(myLocation)); 
     mMap.animateCamera(CameraUpdateFactory.zoomTo(13)); 

    } 

    @Override 
    public void onStatusChanged(String provider, int status, Bundle extras) { 

    } 

    @Override 
    public void onProviderEnabled(String provider) { 

    } 

    @Override 
    public void onProviderDisabled(String provider) { 

    } 
} 

我myItem類以獲取標記信息:越來越顯示

package com.example.tariq.outandabout; 

import com.google.android.gms.maps.model.LatLng; 
import com.google.maps.android.clustering.ClusterItem; 

public class MyItem implements ClusterItem { 
    LatLng mPosition; 
    private String reference,placeTitle,snippet; 

    public MyItem(double lat, double lng,String val,String title, String snip) { 
     mPosition = new LatLng(lat, lng); 
     reference=val; 
     placeTitle=title; 
     snippet = snip; 
    } 

    @Override 
    public LatLng getPosition() { 
     // TODO Auto-generated method stub 
     return mPosition; 
    } 
    public String getReference() { 
     // TODO Auto-generated method stub 
     return reference; 
    } 
    public String getTitle() { 
     // TODO Auto-generated method stub 
     return placeTitle; 
    } 

    public String getSnippet() { 
     // TODO Auto-generated method stub 
     return snippet; 
    } 
} 

目前只有紅色標記,但我在想,如果有一種方法根據從微調器中選擇的類型有不同的標記,例如,如果我選擇醫院,那麼標記顯示爲小醫院圖標,如果我選擇ATM,則會出現一個小的ATM圖標。

任何幫助將不勝感激。

回答

7

首先,你必須存儲你需要的所有信息(在這種情況下只是LatLng和標記圖標)會引入ClusterItem對象。

public class MarkerItem implements ClusterItem { 
private String title; 
private String snippet; 
private LatLng latLng; 
private BitmapDescriptor icon; 

public MarkerItem(MarkerOptions markerOptions) { 
    this.latLng = markerOptions.getPosition(); 
    this.title = markerOptions.getTitle(); 
    this.snippet = markerOptions.getSnippet(); 
    this.icon = markerOptions.getIcon(); 
} 

@Override 
public LatLng getPosition() { 
    return latLng; 
} 

public String getTitle() { 
    return title; 
} 

public String getSnippet() { 
    return snippet; 
} 

public void setLatLng(LatLng latLng) { 
    this.latLng = latLng; 
} 

public BitmapDescriptor getIcon() { 
    return icon; 
} 

public void setIcon(BitmapDescriptor icon) { 
    this.icon = icon; 
} 
} 

下一步將使羣集渲染器顯示您的圖標,而不是默認製造商圖標。要做到這一點,你需要擴展DefaultClusterRenderer對象:

public class ClusterRenderer extends DefaultClusterRenderer<MarkerItem> { 

public ClusterRenderer(Context context, GoogleMap map, ClusterManager<MarkerItem> clusterManager) { 
    super(context, map, clusterManager); 
    clusterManager.setRenderer(this); 
} 


@Override 
protected void onBeforeClusterItemRendered(MarkerItem markerItem, MarkerOptions markerOptions) { 
    if (markerItem.getIcon() != null) { 
     markerOptions.icon(markerItem.getIcon()); //Here you retrieve BitmapDescriptor from ClusterItem and set it as marker icon 
    } 
    markerOptions.visible(true); 
} 
} 

最後,你必須初始化你可以實現你自己的邏輯,你想傳遞給markerItem哪個圖標的clusterRenderer和markerItems

ClusterManager clusterManager = new ClusterManager<>(context, googleMap); 
ClusterRenderer clusterRenderer = new ClusterRenderer<>(activity, googleMap, clusterManager); // not needed to use clusterManager.setRenderer method since i made it in constructor 
MarkerOptions markerOptions = new MarkerOptions() 
      .position(new LatLng(latitude, longitude)) 
      .icon(BitmapDescriptorFactory.fromResource(R.drawable.your_resource_icon)); 
MarkerItem markerItem = new MarkerItem(markerOptions); 
clusterManager.addItem(markerItem); 

這裏。

編輯
要通過不同的圖標,你可以創建爲
實例一個單獨的方法:

public MarkerOptions getMarkerOptions(LatLng latLng, String title, String snippet, int iconRes) { 
    return new MarkerOptions() 
      .title(title) 
      .snippet(snippet) 
      .position(latLng) 
      .icon(BitmapDescriptorFactory.fromResource(iconRes)); 
} 

EDIT 2 我更新MarkerItem類,以滿足您的需求,更換您的MyItem具有MarkerItem類的類。使用此課程添加您的項目並更新以符合您的需求

+0

謝謝您的回覆!該代碼在哪裏適合?或者這將全部成爲一個新的單獨的課程? – T91

+0

ClusterRenderer和MarkerItem可能是一個單獨的公共類,其他初始化代碼會進入活動或您初始化映射的任何位置 –

+0

並且在顯示不同類型的圖標方面,這只是一組if語句?因此,例如'if(types = atm)...'然後其餘的圖標的東西 – T91