google maps iOS SDK: custom icons to be used as markers

The Android API has a very convenient class for this, IconGenerator. Using the IconGenerator in my Android app, I can easily make a marker that:

  1. is a simple rectangle with the color of my choosing.
  2. resizes to hold text of any length.
  3. is NOT an info window - I'd like the marker itself to contain the text as shown in the image below from the android version.

// Android - problem solved with IconGenerator
IconGenerator iconGenerator = new IconGenerator(context);
iconGenerator.setStyle(IconGenerator.STYLE_GREEN); // or any other color
Bitmap iconBitmap = iconGenerator.makeIcon(myString);
Marker m = new MarkerOptions().icon(BitmapDescriptorFactory.fromBitmap(iconBitmap))
                              .position(myLatLng);
map.addMarker(m); // map is a com.google.android.gms.maps.GoogleMap

Is there a way to do something as simple as this in iOS using Swift? There has been a recent release of the iOS api that allows "marker customization", but I don't see how to apply it to this use case.

// iOS (Swift) - I don't know how to create the icon as in code above
let marker = GMSMarker(position: myLatLng)
marker.icon = // How can I set to a rectangle with color/text of my choosing?
marker.map = map // map is a GMSMapView

Answers


Here is what I have done

let marker = GMSMarker()

// I have taken a pin image which is a custom image
let markerImage = UIImage(named: "mapMarker")!.withRenderingMode(.alwaysTemplate)

//creating a marker view
let markerView = UIImageView(image: markerImage)

//changing the tint color of the image
markerView.tintColor = UIColor.red

marker.position = CLLocationCoordinate2D(latitude: 28.7041, longitude: 77.1025)

marker.iconView = markerView
marker.title = "New Delhi"
marker.snippet = "India"
marker.map = mapView

//comment this line if you don't wish to put a callout bubble
mapView.selectedMarker = marker

The output is

And my marker image was

You can change your color as per your need. Also if you want something in rectange, you can just create a simple small rectangular image and use it like I did above and change the color of your need.

Or if you want a rectangle with text within it, you can just create a small UIView with some label and then convert that UIView in UIImage and can do the same thing.

//function to convert the given UIView into a UIImage
func imageWithView(view:UIView) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
    view.layer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image!
}

Hope it helps!!


Here is what i have done for solving the same issue, that you are facing.

I have added below image in my image assets,

Now i added below method in my code:

-(UIImage*)drawText:(NSString*)text inImage:(UIImage*)image
{
    UIFont *font = [UIFont boldSystemFontOfSize:11];
    CGSize size = image.size;
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
    [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
    CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);

    NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    paragraphStyle.alignment = NSTextAlignmentCenter;
    NSDictionary *attributes = @{
                                 NSFontAttributeName : font,
                                 NSParagraphStyleAttributeName : paragraphStyle,
                                 NSForegroundColorAttributeName : [UIColor redColor]
                                 };
    CGSize textSize = [text sizeWithAttributes:attributes];
    CGRect textRect = CGRectMake((rect.size.width-textSize.width)/2, (rect.size.height-textSize.height)/2 - 2, textSize.width, textSize.height);
    [text drawInRect:CGRectIntegral(textRect) withAttributes:attributes];

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

Now, I called this method, while assigning icon to GMSMarker, like this:

marker.icon = [self drawText:@"$33.6" inImage:[UIImage imageNamed:@"icon-marker"]];

It will generate the image icon like below:

Here, I kept the background Image size fixed, as i needed. You can still customize it to adjust it according to text size, as well as multiple lines.


I tried to rewrite Mehul Thakkar answer to Swift 3. Hope it will work for you. But it really easier to make custom view as Dari said.

func drawText(text:NSString, inImage:UIImage) -> UIImage? {

        let font = UIFont.systemFont(ofSize: 11)
        let size = inImage.size

        UIGraphicsBeginImageContext(size)

        inImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
        let style : NSMutableParagraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
        style.alignment = .center
        let attributes:NSDictionary = [ NSFontAttributeName : font, NSParagraphStyleAttributeName : style, NSForegroundColorAttributeName : UIColor.red ]

        let textSize = text.size(attributes: attributes as? [String : Any])
        let rect = CGRect(x: 0, y: 0, width: inImage.size.width, height: inImage.size.height)
        let textRect = CGRect(x: (rect.size.width - textSize.width)/2, y: (rect.size.height - textSize.height)/2 - 2, width: textSize.width, height: textSize.height)
        text.draw(in: textRect.integral, withAttributes: attributes as? [String : Any])
        let resultImage = UIGraphicsGetImageFromCurrentImageContext()

        UIGraphicsEndImageContext()

        return resultImage
    }

You can simply add a custom view as marker in Google Map.

let marker = GMSMarker(position: coordinate)
marker.iconView = view // Your Custom view here

You can use imageView (for containing that orange color box) and label (for text) above it


Here a Swift 5 version of Eridana's Swift conversion of Mehul Thakkar's answer.

func drawTextT(text:NSString, inImage:UIImage) -> UIImage? {

    let font = UIFont.systemFont(ofSize: 11)
    let size = inImage.size

    UIGraphicsBeginImageContext(size)

    inImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    let style : NSMutableParagraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
    style.alignment = .center
    let attributes:NSDictionary = [ NSAttributedString.Key.font : font, NSAttributedString.Key.paragraphStyle : style, NSAttributedString.Key.foregroundColor : UIColor.red ]

    //let textSize = text.size(attributes: attributes as? [String : Any])
    let textSize = text.size(withAttributes: attributes as? [NSAttributedString.Key : Any] )

    let rect = CGRect(x: 0, y: 0, width: inImage.size.width, height: inImage.size.height)
    let textRect = CGRect(x: (rect.size.width - textSize.width)/2, y: (rect.size.height - textSize.height)/2 - 2, width: textSize.width, height: textSize.height)
    text.draw(in: textRect.integral, withAttributes: attributes as? [NSAttributedString.Key : Any]  )

    let resultImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    return resultImage
}

Simplest way to achieve if you have just 1 image :

marker.icon = #imageLiteral(resourceName: "fault_marker")

1) In latest X-Code write `marker.icon = imageLiteral".

2) Double click the dummy image icon appeared just now.

3) select desired image.


Need Your Help

How can I find the newest created file in a directory?

perl last-modified

Is there an elegant way in Perl to find the newest file in a directory (newest by modification date)?

Javascript scrollIntoView() middle alignment?

javascript javascript-events js-scrollintoview

Javascript .scrollIntoView(boolean) provide only two alignment option.