Swift | Show image in Custom GMSMarker - ios

I want to show user's profile picture in my custom marker for google maps. Like all others, I have tried this code in init: of customMarker
self.location = location
position = location
icon = UIImage(named: "live location")
groundAnchor = CGPoint(x: 0.5, y: 1)
Is there any possible way to show another image in the circle of the marker icon. ex. using xib.

You can use given two methods:
func drawImageWithProfilePic(pp: UIImage, image: UIImage) -> UIImage {
let imgView = UIImageView(image: image)
let picImgView = UIImageView(image: pp)
picImgView.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
imgView.addSubview(picImgView)
picImgView.center.x = imgView.center.x
picImgView.center.y = imgView.center.y - 7
picImgView.layer.cornerRadius = picImgView.frame.width/2
picImgView.clipsToBounds = true
imgView.setNeedsLayout()
picImgView.setNeedsLayout()
let newImage = imageWithView(view: imgView)
return newImage
}
func imageWithView(view: UIView) -> UIImage {
var image: UIImage?
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
if let context = UIGraphicsGetCurrentContext() {
view.layer.render(in: context)
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
return image ?? UIImage()
}
Here pp is your profile pic and image is the pic icon.
You can set the frame of Profile pic according to you.
I have tried this:
Edit
let marker = GMSMarker(position: coordinate)
marker.icon = drawImageWithProfilePic(pp: imgPP, image: img)
marker.appearAnimation = GMSMarkerAnimation.pop
marker.map = viewGoogleMap
and here is the output:

//put this code where you get image
let url = URL(string: "your_imageUrlString")
let data = try? Data(contentsOf: url!)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: Double(lat)!, longitude: Double(long)!)
marker.icon = self.drawImageWithProfilePic(pp: UIImage.init(data:data!)!, image: UIImage.init(named: "red")!)
marker.title = location
marker.snippet = name + " " + mobile
marker.appearAnimation = GMSMarkerAnimation.pop
marker.map = self.mapView
//put this code in your viewController class
func drawImageWithProfilePic(pp: UIImage, image: UIImage) -> UIImage {
let imgView = UIImageView(image: image)
imgView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
let picImgView = UIImageView(image: pp)
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 - 7
picImgView.layer.cornerRadius = picImgView.frame.width/2
picImgView.clipsToBounds = true
imgView.setNeedsLayout()
picImgView.setNeedsLayout()
let newImage = imageWithView(view: imgView)
return newImage
}
func imageWithView(view: UIView) -> UIImage {
var image: UIImage?
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
if let context = UIGraphicsGetCurrentContext() {
view.layer.render(in: context)
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
return image ?? UIImage()
}
//here "red" is dummy background image

You can create/design a custom view either in nib or programmatically and then assign it to your marker like this.
let someView = YourCustomView()
someView.markerImageView.image = UIImage(named: "markerImage")
someView.userImageView.image = UIImage(named: "userImage")
let marker = GMSMarker()
marker.map = yourMapView
marker.position = somePositionCoordinate;
marker.iconView = someView

Related

How do you display an image at the maximum available space?

I check if the image is vertical or horizontal. If it is horizontal, I rotate it:
#IBOutlet private weak var img: UIImageView!
img.image = file.image
let imageSize = file.image?.size
let imgWidth = imageSize?.width ?? 0
let imgHeight = imageSize?.height ?? 0
if imgWidth > imgHeight {
print("IMG HORIZONTAL")
imgDetail.transform = imgDetail.transform.rotated(by: .pi / 2)
} else {
print("IMG VERTICAL")
}
But it leaves me a space around the image. I would like it to be at the maximum size of the UIImageView.
Try this, declare your imageView:
let YourImageView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "myImage")?.withRenderingMode(.alwaysOriginal)
iv.backgroundColor = .clear
iv.contentMode = .scaleAspectFit
iv.isUserInteractionEnabled = true
iv.clipsToBounds = true
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
in viewDidLoad set if statement and call setupConstraints:
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
guard let imgWidth = YourImageView.image?.size.width else { return }
guard let imgHeight = YourImageView.image?.size.height else { return }
if imgWidth > imgHeight {
print("IMG HORIZONTAL")
guard let image = YourImageView.image else { return }
let newImage = image.rotate(radians: .pi / 2) // image rotation
YourImageView.image = newImage
} else {
print("IMG VERTICAL")
}
setupConstraints()
}
set up constraints
fileprivate func setupConstraints() {
view.addSubview(YourImageView)
YourImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
YourImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
YourImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
YourImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
}
write image extension
extension UIImage {
func rotate(radians: Float) -> UIImage? {
var newSize = CGRect(origin: CGPoint.zero, size: self.size).applying(CGAffineTransform(rotationAngle: CGFloat(radians))).size
// Trim off the extremely small float value to prevent core graphics from rounding it up
newSize.width = floor(newSize.width)
newSize.height = floor(newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, self.scale)
guard let context = UIGraphicsGetCurrentContext() else { return UIImage()}
// Move origin to middle
context.translateBy(x: newSize.width/2, y: newSize.height/2)
// Rotate around middle
context.rotate(by: CGFloat(radians))
// Draw the image at its center
self.draw(in: CGRect(x: -self.size.width/2, y: -self.size.height/2, width: self.size.width, height: self.size.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
this is the result normal (without image rotate extension call) and rotated (with image rotate extension call):

How to fix the size and the color of my custom marker

I added in my mapView (google maps) a custom markers
func addMarker(place:EClass) {
DispatchQueue.main.async {
guard let coordinates = place.location else {
return
}
self.destination = coordinates
//Custom marker
let markerImage = UIImage(named: "marker 2 copy.png")!.withRenderingMode(.alwaysTemplate)
let markerView = UIImageView(image: markerImage)
self.marker = GMSMarker()
self.marker?.position = coordinates
self.marker?.title = place.name
self.marker?.map = self.mapView
self.marker?.iconView = markerView
self.mapView.selectedMarker = self.marker
if self.currentLocation != nil {
self.drawPath(startLocation: self.currentLocation!, endLocation: coordinates)
}
}
}
but the size of it when i run the application is to big, so how can i adjust the size? I have to do it programmatically or i have to change the size of the png i added in my project? Also the color is not same of my png (that is red and black), when i run the application my custom marker appears white.
Try to use GMSMarker.icon not GMSMarker.iconView
let markerImage = UIImage(named: "marker 2 copy.png")!.withRenderingMode(.alwaysTemplate)
self.marker?.icon = self.image(markerImage, scaledToSize: CGSize(width: 20, height: 20))
//Image function
fileprivate func image(_ originalImage:UIImage, scaledToSize:CGSize) -> UIImage {
if originalImage.size.equalTo(scaledToSize) {
return originalImage
}
UIGraphicsBeginImageContextWithOptions(scaledToSize, false, 0.0)
originalImage.draw(in: CGRect(x: 0, y: 0, width: scaledToSize.width, height: scaledToSize.height))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}

add a permanent label below a marker swift

I want to add multiple markers to the map view. Each marker having a text label below it always i.e it should always be visible. Also I want to add my own image as its icon.
Herewith I am attaching a screenshot of what I want.
Code Work
func addGroundOverlay(position: CLLocationCoordinate2D, veh_num: String) {
let overlay = GMSGroundOverlay(position: position, icon: newImage(text: veh_num, size: CGSize(width: 150.0, height: 150.0)), zoomLevel: 10)
overlay.bearing = 0
overlay.map = (self.view as! GMSMapView)
}
func newImage(text: String, size: CGSize) -> UIImage {
let data = text.data(using: String.Encoding.utf8, allowLossyConversion: true)
let drawText = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
let textFontAttributes = [
NSAttributedStringKey.font: UIFont(name: "Helvetica Bold", size: 10)!,
NSAttributedStringKey.foregroundColor: UIColor.red,
]
UIGraphicsBeginImageContextWithOptions(size, false, 0)
drawText?.draw(in: CGRect(x: 0,y: 0, width: size.width, height: size.height), withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
Image for what I have tried
result image
I found out the solution, as lack of time I tried for Apple Map, but you try for google map also.
Steps
Get the location where you wanted to show annotation.
Add this point annotation on Map.
Create a UILabel(says, lbl) with text as you wanted.
Add this text on a view (says, viewAn).
Now capture the viewAn and make it image.
Use this image for location marker.
Below is the code work for Apple Map and out of simulator is added below it and it is working properly. Follow the above steps and definatly it will work for google map also.
Code Work
import UIKit
import MapKit
class MapVC: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView! // Apple mapview Outlet
var location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 28.5961279, longitude: 77.1587375)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let anno = MKPointAnnotation();
anno.coordinate = location;
mapView.addAnnotation(anno);
}
// To capture view
func captureScreen(_ viewcapture : UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(viewcapture.frame.size, viewcapture.isOpaque, 0.0)
viewcapture.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!;
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// Don't want to show a custom image if the annotation is the user's location.
guard !(annotation is MKUserLocation) else {
return nil
}
// Better to make this class property
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) {
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
}
else {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
if let annotationView = annotationView {
// Configure your annotation view here
// view for annotation
let viewAn = UIView()
viewAn.frame = CGRect(x: 0, y: 0, width: 80, height: 18)
// label as required
let lbl = UILabel()
lbl.text = "ABC 123"
lbl.textColor = UIColor.black
lbl.backgroundColor = UIColor.cyan
// add label to viewAn
lbl.frame = viewAn.bounds
viewAn.addSubview(lbl)
// capture viewAn
let img = self.captureScreen(viewAn)
annotationView.canShowCallout = true
// set marker
annotationView.image = img
}
return annotationView
}
}
OutPut :
Edit : image trasparency
use this below func
func changeWhiteColorTransparent(_ image: UIImage) -> UIImage {
let rawImageRef = image.cgImage as! CGImage
let colorMasking : [CGFloat] = [222, 255, 222, 255, 222, 255]
UIGraphicsBeginImageContext(image.size)
let maskedImageRef: CGImage = rawImageRef.copy(maskingColorComponents: colorMasking)!
do {
//if in iphone
UIGraphicsGetCurrentContext()?.translateBy(x: 0.0, y: image.size.height)
UIGraphicsGetCurrentContext()?.scaleBy(x: 1.0, y: -1.0)
}
UIGraphicsGetCurrentContext()?.draw(maskedImageRef, in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
let result = UIGraphicsGetImageFromCurrentImageContext() as! UIImage
UIGraphicsEndImageContext()
return result ?? UIImage()
}
Func callie
Replace code of upper annotationview with below
let viewAn = UIView()
viewAn.frame = CGRect(x: 0, y: 0, width: 80, height: 18)
let lbl = UILabel()
lbl.text = "ABC 123"
lbl.textColor = UIColor.black
lbl.backgroundColor = UIColor.clear
viewAn.backgroundColor = UIColor.white
lbl.frame = viewAn.bounds
viewAn.addSubview(lbl)
let img = self.captureScreen(viewAn)
let aImgNew = self.changeWhiteColorTransparent(img)
annotationView.backgroundColor = UIColor.clear
annotationView.canShowCallout = true
annotationView.image = aImgNew
Output:

How to rotate masked image?

Right now my code displays a image like this
It would work if I could just rotate the image clockwise 90 degrees. How would I do this. Code is listed below. I took out some of the unnecessary lines of code for this.
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var screenView: UIImageView!
var image1 = UIImage(named: "w")
func cropImageIntoQuarterSquare(image: UIImage) -> UIImage? {
//shape of mask
let image = photoDispaly.image
let maskingImage = UIImage(named: "mask5")
//where the masking code starts
photoDispaly.image = maskImage(image: image!, mask: maskingImage!)
photoDispaly.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleBottomMargin, .flexibleRightMargin, .flexibleLeftMargin, .flexibleTopMargin]
photoDispaly.contentMode = .scaleAspectFit // OR .scaleAspectFill
photoDispaly.clipsToBounds = true
let originalImageSize: CGSize = image!.size
let smallImageSize = CGSize(width: (originalImageSize.width + 40), height: (originalImageSize.height + 40))
UIGraphicsBeginImageContext(smallImageSize)
image?.draw(at: CGPoint.zero)
let imageResult = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return imageResult
}
#IBOutlet var photoDispaly: UIImageView!
func maskImage(image:UIImage, mask:(UIImage))->UIImage{
let imageReference = image.cgImage
let maskReference = mask.cgImage
let imageMask = CGImage(maskWidth: maskReference!.width,
height: maskReference!.height,
bitsPerComponent: maskReference!.bitsPerComponent,
bitsPerPixel: maskReference!.bitsPerPixel,
bytesPerRow: maskReference!.bytesPerRow,
provider: maskReference!.dataProvider!, decode: nil, shouldInterpolate: true)
let maskedReference = imageReference!.masking(imageMask!)
let maskedImage = UIImage(cgImage:maskedReference!)
return maskedImage
}
func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
return
} else {
return
}
}
you could run a transform on your UIImageView in your ViewDidLoad function
photoDispaly.transform = CGAffineTransform(rotationAngle: M_PI/4)
also you may want to rename Dispaly to Display ;)

Add a text label to a polygon in google maps for iOS swift

How do I add a text label on a polygon in Google Maps in iOS ? I tried to add an overlay but it will only accept images not text? I am using google maps for ios with Swift on iOS 9.
This is the portion of code troubling me :
func updateUIMap(){
var str = "Hello"
var data = str.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
var drawText = NSString(data: data!, encoding: NSUTF8StringEncoding)
let size = CGSize(width: 24.0,height: 24.0)
var inImage = UIImage()
var textColor: UIColor = UIColor.blackColor()
var textFont: UIFont = UIFont(name: "Helvetica Bold", size: 12)!
UIGraphicsBeginImageContext(size)
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
]
inImage.drawInRect(CGRectMake(0, 0, size.width, size.height))
var rect: CGRect = CGRectMake(24, 24, size.width, size.height)
drawText.drawInRect(rect, withAttributes: textFontAttributes)
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
var overlay = GMSGroundOverlay(position: myposition, icon: newImage, zoomLevel:20)
overlay.bearing = 0
overlay.map = self.mapView
}
Your UIGraphics drawing method might not be correct, you can try the following code to make a new image from a text:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
super.viewDidLoad()
let camera = GMSCameraPosition.cameraWithLatitude(40.712216,
longitude: -74.22655, zoom: 10)
let mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
mapView.myLocationEnabled = true
self.view = mapView
addGroundOverlay(camera.target)
}
func newImage(text: String, size: CGSize) -> UIImage {
let data = text.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
let drawText = NSString(data: data!, encoding: NSUTF8StringEncoding)
let textFontAttributes = [
NSFontAttributeName: UIFont(name: "Helvetica Bold", size: 20)!,
NSForegroundColorAttributeName: UIColor.redColor(),
]
UIGraphicsBeginImageContextWithOptions(size, false, 0)
drawText?.drawInRect(CGRectMake(0, 0, size.width, size.height), withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
func addGroundOverlay(position: CLLocationCoordinate2D) {
let overlay = GMSGroundOverlay(position: position, icon: newImage("Hello StackOverflow", size: CGSizeMake(150.0, 150.0)), zoomLevel: 10)
overlay.bearing = 0
overlay.map = (self.view as! GMSMapView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I've found personally that the easiest way to do this is by adding a GMSMarker with a UILabel as it's iconView property.
let labelMarker = GMSMarker(position: coordinate)
let label = UILabel()
label.text = "Hello friends"
label.sizeToFit()
labelMarker.iconView = label
labelMarker.map = mapView
This approach can run into performance issues if you're adding a TON of markers to the map, but it's very effective if you need to add some labels to a map.

Resources