Android maps utils cluster icon color

前端 未结 6 1582
谎友^
谎友^ 2020-12-13 07:23

Is there any method to change the background color of the cluster item? (the one that displays the count of the markers, like 100+, 200+ ...). I tried to look into the sourc

相关标签:
6条回答
  • 2020-12-13 07:35

    I was able to get a rough implementation working by using this demo from the library samples as a guide.

    I used the lens icon from the Material Design Icons from here. After downloading the lens zip I put ic_lens_black_24dp.png under the drawable folder. Then I used the Drawable.setColorFilter() method to change the default color in the code.

    I was also able to change the default Marker color, and figured I would include that as well here.

    First, set a Renderer by calling setRenderer():

     mClusterManager.setRenderer(new MyClusterRenderer(this, mMap,
                    mClusterManager));
    

    Then, define the MyClusterRenderer class:

    public class MyClusterRenderer extends DefaultClusterRenderer<MyItem> {
    
        private final IconGenerator mClusterIconGenerator = new IconGenerator(getApplicationContext());
    
        public MyClusterRenderer(Context context, GoogleMap map,
                                 ClusterManager<MyItem> clusterManager) {
            super(context, map, clusterManager);
        }
    
        @Override
        protected void onBeforeClusterItemRendered(MyItem item,
                                                   MarkerOptions markerOptions) {
    
            BitmapDescriptor markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA);
    
            markerOptions.icon(markerDescriptor);
        }
    
        @Override
        protected void onClusterItemRendered(MyItem clusterItem, Marker marker) {
            super.onClusterItemRendered(clusterItem, marker);
        }
    
        @Override
        protected void onBeforeClusterRendered(Cluster<MyItem> cluster, MarkerOptions markerOptions){
    
            final Drawable clusterIcon = getResources().getDrawable(R.drawable.ic_lens_black_24dp);
            clusterIcon.setColorFilter(getResources().getColor(android.R.color.holo_orange_light), PorterDuff.Mode.SRC_ATOP);
    
            mClusterIconGenerator.setBackground(clusterIcon);
    
            //modify padding for one or two digit numbers
            if (cluster.getSize() < 10) {
                mClusterIconGenerator.setContentPadding(40, 20, 0, 0);
            }
            else {
                mClusterIconGenerator.setContentPadding(30, 20, 0, 0);
            }
    
            Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
            markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
        }
    }
    

    Full class code:

    public class MapsActivity extends AppCompatActivity
            implements ClusterManager.OnClusterItemInfoWindowClickListener<MyItem> {
    
        private ClusterManager<MyItem> mClusterManager;
        private MyItem clickedClusterItem;
        private GoogleMap mMap;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_maps);
    
            setUpMapIfNeeded();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            setUpMapIfNeeded();
        }
    
    
        private void setUpMapIfNeeded() {
            // Do a null check to confirm that we have not already instantiated the map.
            if (mMap == null) {
                // Try to obtain the map from the SupportMapFragment.
                mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
                        .getMap();
    
                // Check if we were successful in obtaining the map.
                if (mMap != null) {
                    setUpMap();
                }
    
            }
        }
    
        private void setUpMap() {
    
            mMap.getUiSettings().setMapToolbarEnabled(true);
            mMap.getUiSettings().setZoomControlsEnabled(true);
            mMap.setMyLocationEnabled(true);
            mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
    
            mClusterManager = new ClusterManager<>(this, mMap);
    
            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.779977,-122.413742), 10));
    
            mMap.setOnCameraChangeListener(mClusterManager);
            mMap.setOnMarkerClickListener(mClusterManager);
    
            mClusterManager.setRenderer(new MyClusterRenderer(this, mMap,
                    mClusterManager));
    
            mMap.setInfoWindowAdapter(mClusterManager.getMarkerManager());
    
            mMap.setOnInfoWindowClickListener(mClusterManager); //added
            mClusterManager.setOnClusterItemInfoWindowClickListener(this); //added
    
            mClusterManager
                    .setOnClusterItemClickListener(new ClusterManager.OnClusterItemClickListener<MyItem>() {
                        @Override
                        public boolean onClusterItemClick(MyItem item) {
                            clickedClusterItem = item;
                            return false;
                        }
                    });
    
    
    
            addItems();
    
            mClusterManager.getMarkerCollection().setOnInfoWindowAdapter(
                    new MyCustomAdapterForItems());
    
        }
    
        private void addItems() {
    
            double latitude = 37.779977;
            double longitude = -122.413742;
            for (int i = 0; i < 10; i++) {
                double offset = i / 60d;
    
                double lat = latitude + offset;
                double lng = longitude + offset;
                MyItem offsetItem = new MyItem(lat, lng, "title " + i+1, "snippet " + i+1);
                mClusterManager.addItem(offsetItem);
    
            }
    
        }
    
        //added with edit
        @Override
        public void onClusterItemInfoWindowClick(MyItem myItem) {
    
            //Cluster item InfoWindow clicked, set title as action
            Intent i = new Intent(this, OtherActivity.class);
            i.setAction(myItem.getTitle());
            startActivity(i);
    
            //You may want to do different things for each InfoWindow:
            if (myItem.getTitle().equals("some title")){
    
                //do something specific to this InfoWindow....
    
            }
    
        }
    
        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;
            }
        }
    
        public class MyClusterRenderer extends DefaultClusterRenderer<MyItem> {
    
            private final IconGenerator mClusterIconGenerator = new IconGenerator(getApplicationContext());
    
            public MyClusterRenderer(Context context, GoogleMap map,
                                     ClusterManager<MyItem> clusterManager) {
                super(context, map, clusterManager);
            }
    
            @Override
            protected void onBeforeClusterItemRendered(MyItem item,
                                                       MarkerOptions markerOptions) {
    
                BitmapDescriptor markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA);
    
                markerOptions.icon(markerDescriptor);
            }
    
            @Override
            protected void onClusterItemRendered(MyItem clusterItem, Marker marker) {
                super.onClusterItemRendered(clusterItem, marker);
            }
    
            @Override
            protected void onBeforeClusterRendered(Cluster<MyItem> cluster, MarkerOptions markerOptions){
    
                final Drawable clusterIcon = getResources().getDrawable(R.drawable.ic_lens_black_24dp);
                clusterIcon.setColorFilter(getResources().getColor(android.R.color.holo_orange_light), PorterDuff.Mode.SRC_ATOP);
    
                mClusterIconGenerator.setBackground(clusterIcon);
    
                //modify padding for one or two digit numbers
                if (cluster.getSize() < 10) {
                    mClusterIconGenerator.setContentPadding(40, 20, 0, 0);
                }
                else {
                    mClusterIconGenerator.setContentPadding(30, 20, 0, 0);
                }
    
                Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
                markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
            }
        }
    }
    

    Result:

    Initial app launch:

    No clustering

    Zooming out, some clustering:

    initial clustering

    Zooming out again, all Markers clustered:

    all Markers clustered

    0 讨论(0)
  • 2020-12-13 07:35

    Sadly, overriding getColor doesn't work for me. But this looks enough to change the marker color (and something else):

    class ClusterItemRenderer(
        context: Context, map: GoogleMap,
        clusterManager: ClusterManager<ClusterMarker>
    ) : DefaultClusterRenderer<ClusterMarker>(context, map, clusterManager) {
    
        override fun onBeforeClusterItemRendered(item: ClusterMarker, markerOptions: MarkerOptions) {
            val markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)
            markerOptions.icon(markerDescriptor)
        }
    }
    

    It's also possible to add updates according to the recommendations:

    If you're using custom clustering (i.e, if you're extending DefaultClusterRenderer), you must override two additional methods in v1:

    • onClusterItemUpdated() - should be the same* as your onBeforeClusterItemRendered() method
    • onClusterUpdated() - should be the same* as your onBeforeClusterRendered() method

    *Note that these methods can't be identical, as you need to use a Marker instead of MarkerOptions

    override fun onClusterItemUpdated(item: ClusterMarker, marker: Marker) {
        val markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)
        marker.setIcon(markerDescriptor)
    }
    
    0 讨论(0)
  • 2020-12-13 07:43

    I took some methods of superclass and partially remade them. Now i have beautiful standard clusters with my own colors.

    public class CustomClusterRenderer extends DefaultClusterRenderer<GoogleMapMarker> {
    
    private final IconGenerator mIconGenerator;
    private ShapeDrawable mColoredCircleBackground;
    private SparseArray<BitmapDescriptor> mIcons = new SparseArray();
    private final float mDensity;
    private Context mContext;
    
    public CustomClusterRenderer(Context context, GoogleMap map,
                                 ClusterManager<GoogleMapMarker> clusterManager) {
        super(context, map, clusterManager);
    
    
        this.mContext = context;
        this.mDensity = context.getResources().getDisplayMetrics().density;
        this.mIconGenerator = new IconGenerator(context);
        this.mIconGenerator.setContentView(this.makeSquareTextView(context));
        this.mIconGenerator.setTextAppearance(
                com.google.maps.android.R.style.ClusterIcon_TextAppearance);
        this.mIconGenerator.setBackground(this.makeClusterBackground());
    }
    
    @Override
    protected void onBeforeClusterRendered(Cluster<GoogleMapMarker> cluster,
                                           MarkerOptions markerOptions) {
        // Main color
        int clusterColor = mContext.getResources().getColor(R.color.colorPrimary);
    
        int bucket = this.getBucket(cluster);
        BitmapDescriptor descriptor = this.mIcons.get(bucket);
        if(descriptor == null) {
            this.mColoredCircleBackground.getPaint().setColor(clusterColor);
            descriptor = BitmapDescriptorFactory.fromBitmap(
                    this.mIconGenerator.makeIcon(this.getClusterText(bucket)));
            this.mIcons.put(bucket, descriptor);
        }
    
        markerOptions.icon(descriptor);
    }
    
    private SquareTextView makeSquareTextView(Context context) {
        SquareTextView squareTextView = new SquareTextView(context);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(-2, -2);
        squareTextView.setLayoutParams(layoutParams);
        squareTextView.setId(com.google.maps.android.R.id.text);
        int twelveDpi = (int)(12.0F * this.mDensity);
        squareTextView.setPadding(twelveDpi, twelveDpi, twelveDpi, twelveDpi);
        return squareTextView;
    }
    
    private LayerDrawable makeClusterBackground() {
        // Outline color
        int clusterOutlineColor = mContext.getResources().getColor(R.color.colorWhite);
    
        this.mColoredCircleBackground = new ShapeDrawable(new OvalShape());
        ShapeDrawable outline = new ShapeDrawable(new OvalShape());
        outline.getPaint().setColor(clusterOutlineColor);
        LayerDrawable background = new LayerDrawable(
                new Drawable[]{outline, this.mColoredCircleBackground});
        int strokeWidth = (int)(this.mDensity * 3.0F);
        background.setLayerInset(1, strokeWidth, strokeWidth, strokeWidth, strokeWidth);
        return background;
    }
    

    And then set renderer to Cluster Manager

    mClusterManager = new ClusterManager<>(context, mGoogleMap);
    mClusterManager.setRenderer(new CustomClusterRenderer(context, mGoogleMap, mClusterManager));
    
    0 讨论(0)
  • 2020-12-13 07:45

    Nice custom renderer with centered text and different sizes of clusters:

      public class MyClusterRenderer extends DefaultClusterRenderer<Station> {
    
        private final IconGenerator mClusterIconGeneratorBig = new IconGenerator(getCtx());
        private final IconGenerator mClusterIconGeneratorMed = new IconGenerator(getCtx());
        private final IconGenerator mClusterIconGeneratorSml = new IconGenerator(getCtx());
        final Drawable clusterIconBig = getResources().getDrawable(R.drawable.marker1);
        final Drawable clusterIconMed = getResources().getDrawable(R.drawable.marker2);
        final Drawable clusterIconSml = getResources().getDrawable(R.drawable.marker3);
    
        public MyClusterRenderer(Context context, GoogleMap map,
                                 ClusterManager<Station> clusterManager) {
            super(context, map, clusterManager);
            setupIconGen(mClusterIconGeneratorBig, clusterIconBig, context);
            setupIconGen(mClusterIconGeneratorMed, clusterIconMed, context);
            setupIconGen(mClusterIconGeneratorSml, clusterIconSml, context);
        }
    
        private void setupIconGen(IconGenerator generator, Drawable drawable, Context context) {
            TextView textView = new TextView(context);
            textView.setTextAppearance(context, R.style.BubbleText);
            textView.setTypeface(App.FONTS[2]);
            textView.setId(com.google.maps.android.R.id.amu_text);
            textView.setGravity(android.view.Gravity.CENTER);
            textView.setLayoutParams(new FrameLayout.LayoutParams(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()));
            generator.setContentView(textView);
            generator.setBackground(drawable);
        }
    
        @Override
        protected void onBeforeClusterItemRendered(Station item, MarkerOptions markerOptions) {
            BitmapDescriptor markerDescriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA);
            markerOptions.icon(markerDescriptor);
        }
    
        @Override
        protected void onClusterItemRendered(Station clusterItem, Marker marker) {
            super.onClusterItemRendered(clusterItem, marker);
        }
    
        @Override
        protected void onBeforeClusterRendered(Cluster<Station> cluster, MarkerOptions markerOptions) {
            if (cluster.getSize() > 20) {
                Bitmap icon = mClusterIconGeneratorBig.makeIcon(String.valueOf(cluster.getSize()));
                markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
            } else if (cluster.getSize() > 10) {
                Bitmap icon = mClusterIconGeneratorMed.makeIcon(String.valueOf(cluster.getSize()));
                markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
            } else {
                Bitmap icon = mClusterIconGeneratorSml.makeIcon(String.valueOf(cluster.getSize()));
                markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
            }
        }
    
        @Override
        protected boolean shouldRenderAsCluster(Cluster cluster) {
            return cluster.getSize() > 5;
        }
    }
    

    0 讨论(0)
  • 2020-12-13 07:50

    Go to DefaultClusterRenderer (package com.google.maps.android.clustering.view;), and change the getColor() method to this:

    private int getColor(int clusterSize) {
            // custom color
            double _logClusterSize; // log
            final int _maxRed = Integer.parseInt("ff", 16);
    //        Log.v("kai", String.valueOf(_maxRed));
            final int _minRed = Integer.parseInt("e6", 16);
            final int _maxGreen = Integer.parseInt("a2", 16);
            final int _minGreen = Integer.parseInt("47", 16);
            final int _maxBlue = Integer.parseInt("93", 16);
            final int _minBlue = Integer.parseInt("2d", 16);
            final double _maxLogClusterSize = 10;
            double _step = (_maxRed - _minRed) / _maxLogClusterSize;
    
            _logClusterSize = Math.log(clusterSize);
            if(_logClusterSize > 10) _logClusterSize = 10;
    
            int _red = _maxRed - (int) (_step * _logClusterSize);
            int _green = _maxGreen - (int) (_step * _logClusterSize);
            int _blue = _maxBlue - (int) (_step * _logClusterSize);
    
            return Color.rgb(_red, _green, _blue);
    
    //        final float hueRange = 220;
    //        final float sizeRange = 300;
    //        final float size = Math.min(clusterSize, sizeRange);
    //        final float hue = (sizeRange - size) * (sizeRange - size) / (sizeRange * sizeRange) * hueRange;
    //        return Color.HSVToColor(new float[]{
    //                hue, 1f, .6f
    //        });
        }
    

    This will change the Cluster color to pink, in the range of the color defined by min(max) red(green, blue). Hope that help!

    0 讨论(0)
  • 2020-12-13 08:00

    We can Override getColor in CustomClusterRenderer.

    public class CustomClusterRenderer extends DefaultClusterRenderer<CustomClusterItem> {
    
    @Override
        protected int getColor(int clusterSize) {
            return Color.parseColor("#567238");
        }
    }
    
    0 讨论(0)
提交回复
热议问题