Custom Marker using GMUClusterManager

≯℡__Kan透↙ 提交于 2020-01-09 21:13:02

问题


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.


回答1:


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:




回答2:


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)



回答3:


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;



回答4:


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

}



回答5:


You may want to check out the tutorial - Marker Clustering with Google's Utility library for Maps SDK (Google-Maps-iOS-Utils), this present a perfect sample on the things you want to implement on your app. There are also Google sample codes from the blog that you might want to try. Lastly there was an issue reported in github about Way to customize individual markers added to cluster manager?, it might help you understand how to customize the markers in GMUClusterManager. Hope this helps.



来源:https://stackoverflow.com/questions/40837717/custom-marker-using-gmuclustermanager

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!