2016-04-09 4 views
2

Я работаю над небольшим приложением и реализовал Google Maps и Places 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; 
    } 
} 

В настоящее время только красные маркеры, но мне было интересно, если есть способ иметь разные маркеры в зависимости от типа, выбранного из счетчика. Например, если я выбираю «Больница», маркеры отображаются как маленькие значки больницы, если я выбираю банкомат, появляется значок банкомата.

Любая помощь будет оценена по достоинству.

ответ

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

Наконец, вы должны инициализировать 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); 

Вы можете реализовать свою собственную логику, которая значок вы хотите передать markerItem Вот.

EDIT
Чтобы передать различные иконки, вы можете создать отдельный метод для этого
Пример:

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

Смежные вопросы