I want to display Custom marker using GMUClusterManager
. I followed all steps for marker clustering here.
but there is blue and red color Icon like this.
But when I Zoom in that map it display only red color Marker but I don't want that.
there is instance method where I have implemented my logic but no use.
- (instancetype)initWithMapView:(GMSMapView *)mapView clusterIconGenerator:(id<GMUClusterIconGenerator>)iconGenerator
{
if ((self = [super init])) {
GMSMarker *marker= [GMSMarker markerWithPosition:CLLocationCoordinate2DMake(24.0, 75.30)];
UIView *customMarker =[[UIView alloc] initWithFrame:CGRectMake(0, 0, 63, 40)];
customMarker.backgroundColor = [UIColor blueColor];
marker.iconView = [self EmployeeMarker:0] ;
marker.appearAnimation = kGMSMarkerAnimationPop;
marker.map = mapView;
}
return self;
}
-(UIView *)EmployeeMarker:(int)labelTextInt{
UIView *customMarker =[[UIView alloc] initWithFrame:CGRectMake(0, 0, 63, 40)];
UIImageView *imgViewCustomMarker = [[UIImageView alloc]initWithFrame:CGRectMake(0, 15, 24, 25)];
imgViewCustomMarker.image = [UIImage imageNamed:@"iconMapUser.png"];
[customMarker addSubview:imgViewCustomMarker];
UIView *viewRatingCustom = [[UIView alloc] initWithFrame:CGRectMake(15, 0, 40, 15)];
viewRatingCustom.backgroundColor = [UIColor colorWithRed:192.0/255.0 green:192.0/255.0 blue:192.0/255.0 alpha:1.0];
UILabel *lblRatingEmployees = [[UILabel alloc] initWithFrame:CGRectMake(8, 1, 17,8)];
lblRatingEmployees.textColor = [UIColor colorWithRed:0.00/255.0 green:100.0/255.0 blue:150.0/255.0 alpha:1.0];
lblRatingEmployees.text = @"1";
lblRatingEmployees.font = [UIFont fontWithName:@"Helvetica-Bold" size:10];
[lblRatingEmployees sizeToFit];
[viewRatingCustom addSubview:lblRatingEmployees];
UIImageView *imageViewStar = [[UIImageView alloc] initWithFrame:CGRectMake(25, 3, 10, 8)];
imageViewStar.image = [UIImage imageNamed:@"iconBlueStar.png"];
[viewRatingCustom addSubview:imageViewStar];
[customMarker addSubview:viewRatingCustom];
return customMarker;
}
I have used this method for display possible number of Marker that is by default red.
id<GMUClusterAlgorithm> algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init];
id<GMUClusterIconGenerator> iconGenerator = [[GMUDefaultClusterIconGenerator alloc] init];
id<GMUClusterRenderer> renderer =
[[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView
clusterIconGenerator:iconGenerator];
_clusterManager =
[[GMUClusterManager alloc] initWithMap:_mapView algorithm:algorithm renderer:renderer];
// Generate and add random items to the cluster manager.
// [self generateClusterItems];
for (int i = 0; i<latitudeArray.count; i++) {
id<GMUClusterItem> item =
[[POIItem alloc]initWithPosition:CLLocationCoordinate2DMake([[latitudeArray objectAtIndex:i]doubleValue], [[longitudeArray objectAtIndex:i]doubleValue]) name:@"Name"];
[_clusterManager addItem:item];
}
Adde delegates and also cluster method.
[_clusterManager cluster];
[_clusterManager setDelegate:self mapDelegate:self];
So please help me for adding custom marker in place of red that is in default.
In Swift 4.2 :
add this exstention to your controller and be sure that your controller is the delegate of GMUClusterRendererDelegate
:
willRenderMarker
will call each time a marker going to be render (both cluster marker and clusterItemMarker so you can check it by simple if).so you can modify it's icon and etc before showing it to user
extension YourController: GMUClusterRendererDelegate {
func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) {
// if your marker is pointy you can change groundAnchor
marker.groundAnchor = CGPoint(x: 0.5, y: 1)
if let markerData = (marker.userData as? PersonMarker) {
let icon = markerData.imageURL
marker.iconView = CustomMarkerView(forUrl: url)
}
}
}
And PersonMarker is your marker class that subclass NSObject
and GMUClusterItem
: (you can use default class of GMUClusterItem
but if you need some other properties you can subclass it)
class PersonMarker: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
var imageURL : String?
var name: String?
var userdId: String?
var lastSeen: String?
init(position: CLLocationCoordinate2D, url: String?, name: String?, userId: String?, lastSeen: String?) {
self.position = position
self.imageURL = url
self.name = name
self.userdId = userId
self.lastSeen = lastSeen
}
}
You can add PersonMarker
to your GMUClusterManager
like this :
let position = CLLocationCoordinate2D(latitude: item.latitude!, longitude: item.longitute!)
let person = PersonMarker(position: position, url: item.user?.avaterUrl, name: item.user?.name, userId: item.user?.userId, lastSeen: item.lastUpdate)
clusterManager.add(person)
You need custom class implementing GMUClusterIconGenerator
with designed func icon(forSize size: UInt) -> UIImage!
method which returns UIImage
for your cluster.
I suggest creating view and functionality to add designed label with cluster's title to it and then creating UIImage
from your UIView
.
Then you'll be able to create your custom cluster generator like this:
let iconGenerator = ClusterIconGenerator()
Example result:
Working generator:
class ClusterIconGenerator: NSObject, GMUClusterIconGenerator {
private struct IconSize {
private let initialFontSize: CGFloat = 12
private let fontMultiplier: CGFloat = 0.1
private let initialSize: CGFloat = 25
private let sizeMultiplier: CGFloat = 0.18
/**
Rounded cluster sizes (like 10+, 20+, etc.)
*/
private let sizes = [10,20,50,100,200,500,1000]
let size: UInt
/**
Returns scale level based on size index in `sizes`. Returns `1` if size doesn't have rounded representation
*/
private var scaleLevel: UInt {
if let index = sizes.lastIndex(where: { $0 <= size }) {
return UInt(index) + 2
} else {
return 1
}
}
/**
Returns designed title from cluster's size
*/
var designedTitle: String {
if let size = sizes.last(where: { $0 <= size }) {
return "\(size)+"
} else {
return "\(size)"
}
}
/**
Returns initial font size multiplied by recursively created multiplier
*/
var designedFontSize: CGFloat {
let multiplier: CGFloat = (1...scaleLevel).reduce(1) { n,_ in n + n * fontMultiplier }
return initialFontSize * multiplier
}
/**
Returns initial `CGSize` multiplied by recursively created multiplier
*/
var designedSize: CGSize {
let multiplier: CGFloat = (1...scaleLevel).reduce(1) { n,_ in n + n * sizeMultiplier }
return CGSize(width: initialSize * multiplier, height: initialSize * multiplier)
}
}
/**
Returns image based on current cluster's size
*/
func icon(forSize size: UInt) -> UIImage! {
let iconSize = IconSize(size: size)
let frame = CGRect(origin: .zero, size: iconSize.designedSize)
let view = UIView(frame: frame)
view.layer.cornerRadius = iconSize.designedSize.height / 2
view.backgroundColor = .green
let label = UILabel(frame: frame)
label.textAlignment = .center
label.textColor = .white
label.text = iconSize.designedTitle
view.addSubview(label)
return view.asImage
}
}
extension UIView {
var asImage: UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}
You need to create custom class, which conforms to GMUClusterIconGenerator
protocol:
CustomClusterIconGenerator.h file
@interface CustomClusterIconGenerator : NSObject
<GMUClusterIconGenerator>
@end
CustomClusterIconGenerator.m file
@implementation CustomClusterIconGenerator
- (UIImage *)iconForSize:(NSUInteger)size {
// Return custom icon for cluster
return [UIImage imageNamed:@"Your Custom Cluster Image"];
}
- (UIImage *)iconForMarker {
// Return custom icon for pin
return [UIImage imageNamed:@"Your Custom Marker Image"];
}
- (CGPoint)markerIconGroundAnchor {
// If your marker icon center shifted, return custom value for anchor
return CGPointMake(0, 0);
}
- (CGPoint)clusterIconGroundAnchor {
// If your cluster icon center shifted, return custom value for anchor
return CGPointMake(0, 0);
}
@end
and then then, instead of
id<GMUClusterIconGenerator> iconGenerator = [[GMUDefaultClusterIconGenerator alloc] init];
use
CustomClusterIconGenerator *iconGenerator = [[GMUDefaultClusterIconGenerator alloc] init];
Here is example from my project:
As of version 1.1.0, new features were added for easy customization of markers (read more).
You can add the GMUClusterRendererDelegate
and GMUDefaultClusterRenderer.h
and add the method - (void)renderer:(id<GMUClusterRenderer>)renderer willRenderMarker:(GMSMarker *)marker;
There, you can customize your markers and clusters. For example:
- (void)renderer:(id<GMUClusterRenderer>)renderer willRenderMarker:(GMSMarker *)marker{
if ([marker.userData conformsToProtocol:@protocol(GMUCluster)]) {
marker.icon=[UIImage imageNamed:@"custom_cluster_image.png"];
}else if ([marker.userData conformsToProtocol:@protocol(GMUClusterItem)]) {
marker.icon=[UIImage imageNamed:@"custom_marker_image.png"];
}
}
Remember to set the delegate properly:
id<GMUClusterRenderer> renderer = [[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView clusterIconGenerator:iconGenerator];
((GMUDefaultClusterRenderer *)renderer).delegate=self;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With