Android 集群管理器图标取决于类型

Android Cluster manager icon depending on type

我正在开发一个小应用程序并已实现 Google 地图和地点 api。目前我能够在地图上看到我所有的标记并且集群工作正常。我能够放大打开的集群并能够看到标记。我有一个具有不同类型的微调器,一旦 selected,该类型就会传递给地点搜索字符串。

这是我的包含聚类的地图代码:

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) {

    }
}

my myItem class 获取标记信息:

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

目前只显示红色标记,但我想知道是否有一种方法可以根据微调器的类型 select 显示不同的标记,例如,如果我 select 医院然后标记显示为小医院图标,如果我 select ATM,则会出现一个小 ATM 图标。

任何帮助将不胜感激。

首先,您必须在 ClusterItem 对象中存储您需要的所有信息(在这种情况下,只有 LatLng 和标记图标)。

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。

编辑
要传递不同的图标,您可以为此创建一个单独的方法
示例:

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

编辑 2 我更新了 MarkerItem class 以满足您的需要,将您的 MyItem class 替换为 MarkerItem class。使用此 class 添加您的项目并更新它以满足您的需求