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

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:
is a simple rectangle with the color of my choosing.
resizes to hold text of any length.
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

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.
UPDATE
Updated code in Swift:
func drawText(text:NSString, inImage:UIImage) -> UIImage? {
let font = UIFont.systemFont(ofSize: 11)
let size = inImage.size
//UIGraphicsBeginImageContext(size)
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(inImage.size, false, scale)
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.black ]
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
}

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

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
}

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 XCode write marker.icon = "imageLiteral".
2) Double click the dummy image icon appeared just now.
3) select desired image.

//func to get Image view
// Url String :- Your image coming from server
//image :- Background image
func drawImageWithProfilePic(urlString:String, image: UIImage) -> UIImageView {
let imgView = UIImageView(image: image)
imgView.frame = CGRect(x: 0, y: 0, width: 90, height: 90)
let picImgView = UIImageView()
picImgView.sd_setImage(with:URL(string: urlString))
picImgView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
imgView.addSubview(picImgView)
picImgView.center.x = imgView.center.x
picImgView.center.y = imgView.center.y-10
picImgView.layer.cornerRadius = picImgView.frame.width/2
picImgView.clipsToBounds = true
imgView.setNeedsLayout()
picImgView.setNeedsLayout()
// let newImage = imageWithView(view: imgView)
// return newImage
return imgView
}
//SHOW ON MAP
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: Double(lat)!, longitude: Double(long)!)
marker.iconView = self.drawImageWithProfilePic(urlString:getProviderImage,image: UIImage.init(named: "red")!)

Simple and easiest way to change icon. just replace these 3 icon (default marker.png) to your icon (1x,2x,3x).
In Google Cluster there was a problem with marker (icon) change.

Related

Draw text in image right corner

I want to draw a text in the top or bottom right corner of an UIImage.
I have an extension which works great to draw the text but the problem is to positioned the text at the right of the screen (because text is cut).
Here is the extension :
extension UIImage {
func addText(drawText: NSString, atPoint: CGPoint, textColor: UIColor?, textFont: UIFont?) -> UIImage{
// Setup the font specific variables
var _textColor: UIColor
if textColor == nil {
_textColor = UIColor.white
} else {
_textColor = textColor!
}
var _textFont: UIFont
if textFont == nil {
_textFont = UIFont.systemFont(ofSize: 50)
} else {
_textFont = textFont!
}
// Setup the image context using the passed image
UIGraphicsBeginImageContext(size)
// Setup the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: _textFont,
NSForegroundColorAttributeName: _textColor,
] as [String : Any]
// Put the image into a rectangle as large as the original image
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
// Create a point within the space that is as bit as the image
let rect = CGRect(x: atPoint.x, y: atPoint.y, width: size.width, height: size.height)
// Draw the text into an image
drawText.draw(in: rect, withAttributes: textFontAttributes)
// Create a new image out of the images we have created
let newImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//Pass the image back up to the caller
return newImage!
}
}
Problem is if the text is too long or too big it will be out of the screen. I would need to change the origin point to write the text from the right to the left so it will take space only on the left and not on the right out of the screen. How could I do that ?
There is a simple function call to get the "bounding box" for a string. You can use that to position where the text should be drawn into the image:
// get the bounding-box for the string
let stringSize = drawText.size(attributes: textFontAttributes)
// position the bounding-box at the bottom-right corner of the image
let x = self.size.width - ceil(stringSize.width)
let y = self.size.height - ceil(stringSize.height)
let rect = CGRect(x: x, y: y, width: stringSize.width, height: stringSize.height)
// Draw the text into an image
drawText.draw(in: rect, withAttributes: textFontAttributes)
Note that this sample code positions the text at bottom-right corner - ignoring the atPoint parameter. You would likely change that to a whichCorner type parameter, and then calculate the x and y position appropriately.
By the way... drawText is a terrible name for a variable - it sounds like a function. Much more readable to use something like textToDraw.
Here is a modified function, using a atCorner parameter, where the values are:
+-----------+
| 0 1 |
| |
| |
| 3 2 |
+-----------+
Edit: Using right-aligned paragraph style (as suggested by Thilina Chamin Hewagama) has some advantages. This edited version will even handle text with "\n" embedded line breaks.
extension UIImage {
func addText(textToDraw: NSString, atCorner: Int, textColor: UIColor?, textFont: UIFont?) -> UIImage {
// Setup the font specific variables
var _textColor: UIColor
if textColor == nil {
_textColor = UIColor.white
} else {
_textColor = textColor!
}
var _textFont: UIFont
if textFont == nil {
_textFont = UIFont.systemFont(ofSize: 50)
} else {
_textFont = textFont!
}
// Setup the image context using the passed image
UIGraphicsBeginImageContext(size)
// Put the image into a rectangle as large as the original image
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let titleParagraphStyle = NSMutableParagraphStyle()
// Setup the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: _textFont,
NSForegroundColorAttributeName: _textColor,
NSParagraphStyleAttributeName: titleParagraphStyle
] as [String : Any]
// get the bounding-box for the string
var stringSize = textToDraw.size(attributes: textFontAttributes)
// draw in rect functions like whole numbers
stringSize.width = ceil(stringSize.width)
stringSize.height = ceil(stringSize.height)
var rect = CGRect(origin: CGPoint.zero, size: self.size)
switch atCorner {
case 1:
// top-right
titleParagraphStyle.alignment = .right
case 2:
// bottom-right
rect.origin.y = self.size.height - stringSize.height
titleParagraphStyle.alignment = .right
case 3:
// bottom-left
rect.origin.y = self.size.height - stringSize.height
default:
// top-left
// don't need to change anything here
break
}
// Draw the text into an image
textToDraw.draw(in: rect, withAttributes: textFontAttributes)
// Create a new image out of the images we have created
let newImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//Pass the image back up to the caller
return newImage!
}
}

Add UILabel on UIImage to create a new UIImage [duplicate]

I have looked around and have been unsuccessful at figuring out how take text, overlay it on an image, and then combine the two into a single UIImage.
I have exhausted Google using the search terms I can think of so if anyone has a solution or at least a hint they can point to it would be greatly appreciated.
I figured it out:
func textToImage(drawText: NSString, inImage: UIImage, atPoint: CGPoint) -> UIImage{
// Setup the font specific variables
var textColor = UIColor.whiteColor()
var textFont = UIFont(name: "Helvetica Bold", size: 12)!
// Setup the image context using the passed image
let scale = UIScreen.mainScreen().scale
UIGraphicsBeginImageContextWithOptions(inImage.size, false, scale)
// Setup the font attributes that will be later used to dictate how the text should be drawn
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
]
// Put the image into a rectangle as large as the original image
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
// Create a point within the space that is as bit as the image
var rect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)
// Draw the text into an image
drawText.drawInRect(rect, withAttributes: textFontAttributes)
// Create a new image out of the images we have created
var newImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//Pass the image back up to the caller
return newImage
}
To call it, you just pass in an image:
textToImage("000", inImage: UIImage(named:"thisImage.png")!, atPoint: CGPointMake(20, 20))
The following links helped me get this straight:
Swift - Drawing text with drawInRect:withAttributes:
How to write text on image in Objective-C (iOS)?
The original goal was to create a dynamic image that I could use in an AnnotaionView such as putting a price at a given location on a map and this worked out great for it.
For Swift 3:
func textToImage(drawText text: NSString, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
let textColor = UIColor.white
let textFont = UIFont(name: "Helvetica Bold", size: 12)!
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, scale)
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
] as [String : Any]
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
let rect = CGRect(origin: point, size: image.size)
text.draw(in: rect, withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
For Swift 4:
func textToImage(drawText text: String, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
let textColor = UIColor.white
let textFont = UIFont(name: "Helvetica Bold", size: 12)!
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, scale)
let textFontAttributes = [
NSAttributedStringKey.font: textFont,
NSAttributedStringKey.foregroundColor: textColor,
] as [NSAttributedStringKey : Any]
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
let rect = CGRect(origin: point, size: image.size)
text.draw(in: rect, withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
For Swift 5:
func textToImage(drawText text: String, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
let textColor = UIColor.white
let textFont = UIFont(name: "Helvetica Bold", size: 12)!
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, scale)
let textFontAttributes = [
NSAttributedString.Key.font: textFont,
NSAttributedString.Key.foregroundColor: textColor,
] as [NSAttributedString.Key : Any]
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
let rect = CGRect(origin: point, size: image.size)
text.draw(in: rect, withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
My simple solution:
func generateImageWithText(text: String) -> UIImage? {
let image = UIImage(named: "imageWithoutText")!
let imageView = UIImageView(image: image)
imageView.backgroundColor = UIColor.clear
imageView.frame = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
let label = UILabel(frame: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
label.backgroundColor = UIColor.clear
label.textAlignment = .center
label.textColor = UIColor.white
label.text = text
UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0)
imageView.layer.render(in: UIGraphicsGetCurrentContext()!)
label.layer.render(in: UIGraphicsGetCurrentContext()!)
let imageWithText = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return imageWithText
}
You can also do a CATextLayer.
// 1
let textLayer = CATextLayer()
textLayer.frame = someView.bounds
// 2
let string = String(
repeating: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce auctor arcu quis velit congue dictum. ",
count: 20
)
textLayer.string = string
// 3
let fontName: CFStringRef = "Noteworthy-Light"
textLayer.font = CTFontCreateWithName(fontName, fontSize, nil)
// 4
textLayer.foregroundColor = UIColor.darkGray.cgColor
textLayer.isWrapped = true
textLayer.alignmentMode = kCAAlignmentLeft
textLayer.contentsScale = UIScreen.main.scale
someView.layer.addSublayer(textLayer)
https://www.raywenderlich.com/402-calayer-tutorial-for-ios-getting-started
I have created an extension for using it everywhere :
import Foundation
import UIKit
extension UIImage {
class func createImageWithLabelOverlay(label: UILabel,imageSize: CGSize, image: UIImage) -> UIImage {
UIGraphicsBeginImageContextWithOptions(CGSize(width: imageSize.width, height: imageSize.height), false, 2.0)
let currentView = UIView.init(frame: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))
let currentImage = UIImageView.init(image: image)
currentImage.frame = CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height)
currentView.addSubview(currentImage)
currentView.addSubview(label)
currentView.layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
}
Usage :
Anywhere on your ViewController where you have the size and the label to add use it as follows -
let newImageWithOverlay = UIImage.createImageWithLabelOverlay(label: labelToAdd, imageSize: size, image: editedImage)
For swift 4:
func textToImage(drawText text: NSString, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, scale)
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
let rect = CGRect(origin: point, size: image.size)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let attrs = [NSAttributedStringKey.font: UIFont(name: "Helvetica Bold", size: 12)!,NSAttributedStringKey.foregroundColor : UIColor.white , NSAttributedStringKey.paragraphStyle: paragraphStyle]
text.draw(with: rect, options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
I can't see anything in your initial question suggesting that this must be done exclusively in code - so why not simply add a UILabel in interface builder, and add constraints to give it the same length and width as your image, center it vertically and horizontally (or however you need it placed), delete the label text, set the text font, size, colour, etc. as needed (including ticking Autoshrink with whatever minimum size or scale you need), and ensure it's background is transparent.
Then just connect it to an IBOutlet, and set the text in code as needed (e.g. in viewWillAppear, or by using a ViewModel approach and setting it on initialisation of your view/viewcontroller).
I have tried this basic components. Hope it will work.
func imageWithText(image : UIImage, text : String) -> UIImage {
let outerView = UIView(frame: CGRect(x: 0, y: 0, width: image.size.width / 2, height: image.size.height / 2))
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: outerView.frame.width, height: outerView.frame.height))
imgView.image = image
outerView.addSubview(imgView)
let lbl = UILabel(frame: CGRect(x: 5, y: 5, width: outerView.frame.width, height: 200))
lbl.font = UIFont(name: "HelveticaNeue-Bold", size: 70)
lbl.text = text
lbl.textAlignment = .left
lbl.textColor = UIColor.blue
outerView.addSubview(lbl)
let renderer = UIGraphicsImageRenderer(size: outerView.bounds.size)
let convertedImage = renderer.image { ctx in
outerView.drawHierarchy(in: outerView.bounds, afterScreenUpdates: true)
}
return convertedImage
}
It's also possible to use the QLPreviewController. Just save the imageFile to an url like the applicationsDocuments directory under the .userDomainMask and open the apple' editor. You can draw, add shapes, arrow and even your signature.
I explained the implementation in detail in the following post:
https://stackoverflow.com/a/68743098/12035498

How to dynamically draw image for button in iOS?

This is the result I need to accomplish:
I need the icons with basic image: basket and additionally I need to put there UILabel with some text: once it is just a number, and once it is an amount to pay. Any ideas?
This is my example:
var image = UIImage(named: "cart")!
let text = "1 PLN"
UIGraphicsBeginImageContext(CGSizeMake(80, 50))
let context = UIGraphicsGetCurrentContext()
let label = UILabel(frame: CGRectZero)
label.text = text
label.font = UIFont.systemFontOfSize(10)
label.sizeToFit()
let width = max(label.frame.size.width + 10, 15)
let height = CGFloat(15)
CGContextSetFillColorWithColor(context, UIColor.greenColor().CGColor)
CGContextFillRect(context, CGRectMake(0, 0, image.size.width, image.size.height))
image.drawInRect(CGRectMake(80/2-50/2, 0, 50, 50))
let path = UIBezierPath(roundedRect: CGRectMake(75-width, 45-height, width, height), cornerRadius: 5)
path.lineWidth = 2
UIColor.redColor().setStroke()
UIColor.yellowColor().setFill()
path.stroke()
path.fill()
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = NSTextAlignment.Center
let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(10.0), NSParagraphStyleAttributeName: paragraphStyle]
(text as NSString).drawInRect(CGRectMake(75-width, 45-height, width, height), withAttributes: attributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
The result is following:
Some examples for different text:

bubble icon factory for google maps in iOS

I had earlier used the google map util library to plot bubble icon in google maps and now I would like to do the same for iOS
https://developers.google.com/maps/documentation/android/utility/
I found this pod for iOS https://github.com/googlemaps/google-maps-ios-utils
Has anybody used it to create bubble icons and if so how do i create a bubble icons for iOS ?
Unfortunately, there is no such utility for IOS. I needed a similar solution, so I've come with the below.
The below function draws a left arrow and returns an UIImage. Note that one can draw the arrow by using only paths. Also, one can also use a pre created image from assets instead of creating all the time or create one re-use it.
func drawArrow() ->UIImage {
//the color of the arrow
let color = UIColor.yellow
// First create empty image choose the size according to your need.
let width = 84
let height = 24
let size = CGSize( width: width, height: height)
//let image: UIImage = makeEmptyImage(size: size)
let rectangle = CGRect(x: 12, y: 0, width: 72, height: 24)
UIGraphicsBeginImageContextWithOptions( size, false, 0.0)
let context = UIGraphicsGetCurrentContext()
//clear the background
context?.clear(CGRect(x: 0, y: 0, width: width, height: height))
//draw the rectangle
context?.addRect(rectangle)
context?.setFillColor(color.cgColor)
context?.fill(rectangle)
//draw the triangle
context?.beginPath()
context?.move( to: CGPoint(x : 12 ,y : 0) )
context?.addLine(to: CGPoint(x : 0, y : 12) )
context?.addLine(to: CGPoint(x : 12, y : 24) )
context?.closePath()
context?.setFillColor(color.cgColor)
context?.fillPath()
// get the image
let image2 = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image2
}
The next function, takes the image and draw a text onto it.
func drawText(text:NSString, inImage:UIImage) -> UIImage? {
let font = UIFont.systemFont(ofSize: 11)
let color = UIColor.black
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 : color
]
let myInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 0)
let newImage = inImage.resizableImage(withCapInsets: myInsets)
print("rect.width \(inImage.size.width) rect.height \(inImage.size.height)")
let textSize = text.size(withAttributes: attributes as? [NSAttributedString.Key : Any] )
let textRect = CGRect(x: 10, y: 5, width: textSize.width, height: textSize.height)
UIGraphicsBeginImageContextWithOptions(CGSize(width: textSize.width + 20, height: textSize.height + 10), false, 0.0)
newImage.draw(in: CGRect(x: 0, y: 0, width: textSize.width + 20 , height: textSize.height + 10))
text.draw(in: textRect.integral, withAttributes: attributes as? [NSAttributedString.Key : Any] )
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
so we can use it like
marker.icon = drawText(text: eLoc.name as NSString, inImage: drawArrow() )
marker.groundAnchor = CGPoint(x: 0, y: 0.5)
//If you need some rotation
//let degrees = CLLocationDegrees(exactly: 90.0)
//marker.rotation = degrees!
groundAnchor moves the position of the marker icon, see this anwser. With degree you can rotate the arrow.
Note : Unfortunately, IOS doesn't support 9-patch images. Therefore, not all of the bubble icon factory can be programmed by using resizableImage, see this nice web site and also see this answer
An example output is;
Have you check out the customize icon documentation for google maps ios sdk? It's a good start.

Add text on custom marker on google map for ios

Am trying to put marker with Textview .Is there any posibility to add text over marker on google map in ios.
Like This
You must make a view, where you must create an imageView (with your marker image) and Label (with your text) and take a screenshot of that view, and set as icon to your GMSMarker.
Something like this:
- (void)foo
{
GMSMarker *marker = [GMSMarker new];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0,60,60)];
UIImageView *pinImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"myPin"]];
UILabel *label = [UILabel new];
label.text = #"1";
//label.font = ...;
[label sizeToFit];
[view addSubview:pinImageView];
[view addSubview:label];
//i.e. customize view to get what you need
UIImage *markerIcon = [self imageFromView:view];
marker.icon = markerIcon;
marker.map = self.mapView;
}
- (UIImage *)imageFromView:(UIView *) view
{
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, [[UIScreen mainScreen] scale]);
} else {
UIGraphicsBeginImageContext(view.frame.size);
}
[view.layer renderInContext: UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
If you want to display something like this , then just follow these steps. It is very simple, You can use this method.
-(UIImage *)createImage:(NSUInteger)count{ //count is the integer that has to be shown on the marker
UIColor *color = [UIColor redColor]; // select needed color
NSString *string = [NSString stringWithFormat:#"%lu",(unsigned long)count]; // the string to colorize
NSDictionary *attrs = #{ NSForegroundColorAttributeName : color };
NSAttributedString *attrStr = [[NSAttributedString alloc] initWithString:string attributes:attrs]; // add Font according to your need
UIImage *image = [UIImage imageNamed:#"ic_marker_orange"]; // The image on which text has to be added
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0,0,image.size.width,image.size.height)];
CGRect rect = CGRectMake(20,5, image.size.width, image.size.height);// change the frame of your text from here
[[UIColor whiteColor] set];
[attrStr drawInRect:rect];
UIImage *markerImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return markerImage;}
and when you set marker to the map then just set
GMSMarker *marker = [[GMSMarker alloc] init];
marker.icon = [self createImage:[model.strFriendCount integerValue]]; // pass any integer to the method.
Here is the Swift 5 version of Kunal's answer:
//count is the integer that has to be shown on the marker
func createImage(_ count: Int) -> UIImage {
let color = UIColor.red
// select needed color
let string = "\(UInt(count))"
// the string to colorize
let attrs: [NSAttributedString.Key: Any] = [.foregroundColor: color]
let attrStr = NSAttributedString(string: string, attributes: attrs)
// add Font according to your need
let image = UIImage(named: "ic_marker_orange")!
// The image on which text has to be added
UIGraphicsBeginImageContext(image.size)
image.draw(in: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(image.size.width), height: CGFloat(image.size.height)))
let rect = CGRect(x: CGFloat(20), y: CGFloat(5), width: CGFloat(image.size.width), height: CGFloat(image.size.height))
attrStr.draw(in: rect)
let markerImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return markerImage
}
Hope this helps someone else.
func createImage(_ count: Int) -> UIImage? {
let string = String(count)
let paragraphStyle = NSMutableParagraphStyle()
let font = UIFont.systemFont(ofSize: 9.5)
paragraphStyle.alignment = .center
let attributes: [NSAttributedString.Key: Any] = [
.font : font,
.foregroundColor: UIColor.black,
.paragraphStyle: paragraphStyle
]
let attrStr = NSAttributedString(string: string, attributes: attributes)
let image = self.imageWithImage(image: UIImage(named: "pin_online.png")!, scaledToSize: CGSize(width: 50.0, height: 60.0))
UIGraphicsBeginImageContext(image.size)
UIGraphicsBeginImageContextWithOptions(image.size, false, 0.0)
image.draw(in: CGRect(x: 0, y: 0, width: CGFloat(image.size.width), height: CGFloat(image.size.height)))
let rect = CGRect(x: 14.7, y: CGFloat(3), width: CGFloat(image.size.width), height: CGFloat(image.size.height))
attrStr.draw(in: rect)
let markerImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return markerImage
}

Resources