I am working with Google maps.
this is my MapModel
struct MapModel: Codable {
let iconUrl: String
let xCoordinate: Double
let yCoordinate: Double
}
I have- let marker = GMSMarker()
I want to set marker.icon from server using my model.
For loading image I use this extension.
extension UIImageView {
func load(str: String) {
let url = URL(string: str)
if let url = url {
self.load.request(with: url)
} else {
self.load(str: "imp.png")
}
}
}
But marker.icon is Uiimage type and this extension is for UIImageview. How can I get marker.icon?
Related
My objective is to convert an address into an Apple Maps link and share it with UIActivityViewController, and when it is clicked, it opens Apple Maps and displays an annotation with the address, along with the "directions" button at the bottom, etc. Pretty much make it seem link someone searched for that address. I am able to convert the address, and share the link. Additionally, when the link is clicked, Apple Maps opens, and is centred on my desired location. However, I am unable to create the annotation and include it in the link. I have attempted to make an annotation with the correct coordinates, but have no clue how to add it to the link. To make things less complicated, I removed the annotation code, but here is what I have so far.
func activityItems(latitude: Double, longitude: Double) -> [AnyObject]? {
//this function does most of the work, creating the link and returning it
var items = [AnyObject]()
let URLString = "https://maps.apple.com?ll=\(latitude),\(longitude)"
if let url = NSURL(string: URLString) {
items.append(url)
}
let locationVCardString = [
"BEGIN:VCARD",
"VERSION:3.0",
"PRODID:-//Joseph Duffy//Blog Post Example//EN",
"N:;Shared Location;;;",
"FN:Shared Location",
"item1.URL;type=pref:\(URLString)",
"item1.X-ABLabel:map url",
"END:VCARD"
].joined(separator: "\n")
guard let vCardData : NSSecureCoding = locationVCardString.data(using: .utf8) as NSSecureCoding? else {
return nil
}
let vCardActivity = NSItemProvider(item: vCardData, typeIdentifier: "kUTTypeVCard" as String)
let annotation = MKPointAnnotation()
annotation.coordinate.latitude = latitude
annotation.coordinate.longitude = longitude
items.append(vCardActivity)
items.append(annotation)
return items
}
#IBAction func sendAddress(_ sender: UIButton) {
//this is the IBAction func, from the button tap. it uses the other function to present the activityViewController.
let address = self.donation.object(forKey: "Address") as! String
let geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(address) { placemarks, error in
if let error = error{
print(error.localizedDescription)
return
}
if let placemarks = placemarks{
if let location = placemarks[0].location{
let lat = location.coordinate.latitude
let long = location.coordinate.longitude
if let shareObject = self.activityItems(latitude: lat, longitude: long) {
// making activity view controller
let textToShare = [ shareObject.first, shareObject.last ]
let activityViewController = UIActivityViewController(activityItems: textToShare as [Any], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view // so that iPads won't crash
// present
self.present(activityViewController, animated: true, completion: nil)
}
}
}
}
}
I want to store a couple of images locally in my app on the user's device.
What I was using until now (it's still in development):
static func filePath(forKey key: String) -> URL? {
let fileManager = FileManager.default
guard let documentURL = fileManager.urls(for: .documentDirectory,
in: FileManager.SearchPathDomainMask.userDomainMask).first else { return nil }
return documentURL.appendingPathComponent(key + ".png")
}
static func savePhoto(imageKey: String) {
if let filePath = Helpers.filePath(forKey: imageKey) {
do {
try Constants.PHOTO_DATA.write(to: filePath, options: .atomic)
} catch {
print("error")
}
} else {
print(" >>> Error during saving photo. Filepath couldn't be created.")
}
}
static func getPhoto(imageKey: String) -> (image: UIImage, placeholder: Bool) {
if let filePath = Helpers.filePath(forKey: imageKey),
let fileData = FileManager.default.contents(atPath: filePath.path),
let image = UIImage(data: fileData) {
// Retrieve image from device
return (image, false)
}
return (UIImage(named: "placeholder")!, true)
}
Now, during testing I realized that it is not working (but I'm almost 100% sure it was working until now, strange..). It is changing the App's container directory upon every launch.
E.g.
Path:
/var/mobile/Containers/Data/Application/1F3E812E-B128-481C-9724-5E39049D6C81/Documents/D5F14199-CFBF-402A-9894-3487976C4C74.png
Restarting the app, then the path it gives (and where it does not find the image):
/var/mobile/Containers/Data/Application/0A9FCE45-1ED4-46EB-A91B-3ECD56E6A31B/Documents/D5F14199-CFBF-402A-9894-3487976C4C74.png
I read a bit and as far as I see it is 'expected' that it is not working, as the app's directory can change any time the user restarts the app. I should use bookmarkData of the URL class.
My problem is that I couldn't get it working with bookmarkData as I don't really see how should I use it, and couldn't understand its behavior based on some example codes/articles I found. Until now I was simply using URLs to store/retrieve the photo but now I should go with this bookmarkData which is a Data type, which confuses me.
I'm not sure what you want your code means, since both Helper and Constants.PHOTO_DATA are unknown. The code that will definitely will save a UIImage in the documents directory is here:
class ImageSaver {
private let imageStore = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first
//Make this static variable to allow access from all objects without instantiating this class
static var shared : AuxiliaryObjects {
return AuxiliaryObjects()
}
/**
Declaration: save(image : UIImage, with fileName: String, and imageName: String?)
Description: This method saves the received image to the persistent store in the documents directory of the user.
- Parameter image: The UIImage object that must be stored in the documents directory.
- Parameter fileName: A string with the name under which the image must be stored.
- Parameter imageName: The name of the image if needed.
*/
func save(image: UIImage, with fileName: String, and imageName: String?) {
let fileStore = imageStore?.appendingPathComponent(fileName)
let imageData = UIImagePNGRepresentation(image)
do {
try imageData?.write(to: fileStore!)
} catch {
print("Couldn't write the image to disk.")
}
}
/**
Declaration: getImage(with fileName: String, with rectangle: CGRect) -> UIImage?
Description: This method retrieves the image with the specified file name and a given size.
- Parameter fileName: a string with the file name to retrieve.
- Parameter rectangle: the size of the image to return.
- Returns: UIImage?, the image retrieved from the documents directory.
*/
func getImage(with fileName: String, with rectangle: CGRect) -> UIImage? {
var returnImage : UIImage?
var imageRectangle = rectangle
do {
imageStoreArray = try FileManager.default.contentsOfDirectory(at: imageStore!, includingPropertiesForKeys: resourceKeys, options: .skipsHiddenFiles) as [NSURL]
} catch {
return returnImage
}
for url in imageStoreArray {
let urlString = url.lastPathComponent
if urlString == fileName {
let retrievedImage = UIImage(contentsOfFile: url.path!)
//When there is no size set, the original size image is returned
if (rectangle.size.height > 0) || (rectangle.size.width > 0) {
let imageWidth = retrievedImage?.size.width
let imageHeight = retrievedImage?.size.height
if imageWidth! > imageHeight!
{
//The picture is wider than it is high
imageRectangle.size.height *= (imageHeight! / imageWidth!)
} else {
imageRectangle.size.width *= (imageWidth! / imageHeight!)
}
UIGraphicsBeginImageContextWithOptions(imageRectangle.size, false, UIScreen.main.scale)
retrievedImage?.draw(in: imageRectangle)
returnImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
} else {
returnImage = retrievedImage
}
}
}
return returnImage
}
}
Let me know if this works for you.
Kind regards,
MacUserT
This is how I create markers and add it to array of overlays:
let text = "1"
let url = URL(string: "http://texttopng.azurewebsites.net/Home/TextToPng?text=\(text)")!
let marker = CustomMarker(coordinate: label.location.coordinate, url: url)
but when I try to do a snapshot:
_ = Snapshot(options: options, accessToken: nil).image { image, error in
//error: Error Domain=MBStaticErrorDomain Code=-1 "Marker overlays must be png, jpg, or webp" UserInfo={NSLocalizedFailureReason=Marker overlays must be png, jpg, or webp}
}
Why it happens like this?
This is what I have tried:
let image = UIImage(named: "icon-card")!
let png = UIImagePNGRepresentation(image)!
let newurl = png.write(withName: "\(text).png")
let marker = CustomMarker(coordinate: label.location.coordinate, url: newurl)
extension Data {
func write(withName name: String) -> URL {
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(name)
try! write(to: url, options: .atomicWrite)
return url
}
}
I'd like to share my code and it works without any issues:
let text = "Hello"
let urlWithText = URL(string: "http://texttopng.azurewebsites.net/Home/TextToPng?text=\(text)")!
let marker = CustomMarker(coordinate: CLLocationCoordinate2D(latitude: 53.705912, longitude: 23.840836), url: urlWithText)
let camera = SnapshotCamera(
lookingAtCenter: CLLocationCoordinate2D(latitude: 53.705912, longitude: 23.840836),
zoomLevel: 12)
let options = SnapshotOptions(
styleURL: URL(string: "mapbox://styles/mapbox/satellite-streets-v9")!,
camera: camera,
size: CGSize(width: 400, height: 200))
options.overlays = [marker]
_ = Snapshot(options: options, accessToken: nil).image { image, error in
_ = image?.jpegData(compressionQuality: 1.0)?.write(withName: "my_snapshot.jpg")
}
I used your extension for Data for saving of jpg file
extension Data {
func write(withName name: String) -> URL {
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(name)
print(url.path)
try! write(to: url, options: .atomicWrite)
return url
}
}
and as result I have a shapshot like this:
I guess you can try use my code or part of it and check with your environment. I use MapboxStatic.swift (0.11.0) Mapbox pod
I want to add custom markers as per follow. I have method for markers on google map, But I want to put users image on marker pin as per below. I have transparent marker image and I want to load user image from url. So image must dynamic. So I cannot put static markers.
//Add Marker
func dropMarker(_ location : CLLocation, _ isHotelLocation: Bool = false,_ memberModel : membersModel? = nil){
let marker = GMSMarker()
let position = self.checkIfMutlipleCoordinates(latitude: Float(location.coordinate.latitude), longitude: Float(location.coordinate.longitude))
marker.position = position
if isHotelLocation == false{
if let url = URL.init(string: memberModel!.avatar_url ?? ""){
let imageView = UIImageView(image: UIImage.init(named: "locationPin"))
imageView.sd_setImage(with: url, placeholderImage: UIImage.init(named: "locationPin"))
marker.iconView = imageView
}else{
marker.icon = UIImage(named : "LocationPlaceholderPin")
}
marker.userData = memberModel
}else{
marker.icon = UIImage(named : "hotelMarker")
hotelLocationMarker = marker
}
marker.map = mapView
arrMarkers.append(marker)
}
Use this extension for downloading image from server:
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) { // for swift 4.2 syntax just use ===> mode: UIView.ContentMode
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() {
self.image = image
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) { // for swift 4.2 syntax just use ===> mode: UIView.ContentMode
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
then add the image as subview to marker image:
var userImage = UIImageView()
userImage.downloaded(from: "user image url")
let userMarkerImage = UIImageView(named: "your marker placeholder")
userMarkerImage.addsubView(userImage)
then set the image to marker:
marker.icon = userMarkerImage
Note
You should set the frame of image before adding as subview
I'm trying to build an application where I can share an address and open that in any navigation app (Google maps, Apple maps, waze,...).
Below is the code that I currently have (after going through pages of google search results including dozens of stackoverflow questions)
#IBAction func navigeer(_ sender: Any) {
var items = [AnyObject]()
let latitude: Double = 52.033809
let longitude: Double = 6.882286
let locationTitle = "Navigate to this address"
let URLString = "https://maps.apple.com?ll=\(latitude),\(longitude)"
guard let cachesPathString = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first else {
print("Error: couldn't find the caches directory.")
return
}
if let url = NSURL(string: URLString) {
items.append(url)
}
let vCardString = [
"BEGIN:VCARD",
"VERSION:3.0",
"N:;Shared Location;;;",
"FN:Shared Location",
"item1.URL;type=pref:http://maps.apple.com/?ll=\(latitude),\(longitude)",
"item1.X-ABLabel:map url",
"END:VCARD"
].joined(separator: "\n")
let vCardFilePath = (cachesPathString as NSString).appendingPathComponent("vCard.loc.vcf")
let nsVCardData = NSURL(fileURLWithPath: vCardFilePath)
let shareItems:Array = [nsVCardData]
let activityController = UIActivityViewController(activityItems: shareItems, applicationActivities: nil)
present(activityController, animated:true, completion: nil)
}
When I run the application on my simulator I get the following:
After clicking the share button
Why don't I get app suggestions like Apple maps or Google maps? I also don't get why it suggests me to copy it to contacts..
Thanks in advance.
To share location using UIActivityViewController, Swift 5
func activityItems(latitude: Double, longitude: Double) -> [AnyObject]? {
var items = [AnyObject]()
let URLString = "https://maps.apple.com?ll=\(latitude),\(longitude)"
if let url = NSURL(string: URLString) {
items.append(url)
}
let locationVCardString = [
"BEGIN:VCARD",
"VERSION:3.0",
"PRODID:-//Joseph Duffy//Blog Post Example//EN",
"N:;Shared Location;;;",
"FN:Shared Location",
"item1.URL;type=pref:\(URLString)",
"item1.X-ABLabel:map url",
"END:VCARD"
].joined(separator: "\n")
guard let vCardData : NSSecureCoding = locationVCardString.data(using: .utf8) as NSSecureCoding? else {
return nil
}
let vCardActivity = NSItemProvider(item: vCardData, typeIdentifier: kUTTypeVCard as String)
items.append(vCardActivity)
return items
}
How to use?
if let shareObject = self.activityItems(latitude: 52.033809, longitude: 6.882286) {
//open UIActivityViewController
}
Reference Link : https://new.josephduffy.co.uk/posts/ios-share-sheets-the-proper-way-locations
Try this..
// if the device has google maps installed in it
if (UIApplication.shared.canOpenURL(NSURL(string:"comgooglemaps://")! as URL)) {
UIApplication.shared.openURL(NSURL(string:
"comgooglemaps://?saddr=&daddr=\(myLatitude),\(myLongitude)&directionsmode=driving")! as URL)
}
// if google maps is not installed, try apple map
else if (UIApplication.shared.canOpenURL(NSURL(string:"http://maps.apple.com/maps")! as URL)) {
// apple map
let url = "http://maps.apple.com/maps?saddr=\(from.latitude),\(from.longitude)&daddr=\(to.latitude),\(to.longitude)"
UIApplication.shared.openURL(URL(string:url)!)
}
// if apple map is also not there, it will show an appStore link to download apple map application.