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
Related
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?
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 am getting image from microsoft account by using this api :
https://graph.microsoft.com/beta/me/photo
And this api gets this data which is shown in output. But i don't know how to show this link into image in Swift.
Output :
"#odata.context" = "https://graph.microsoft.com/beta/$metadata#users('rahulchopra.93%40outlook.com')/photo/$entity";
"#odata.mediaContentType" = "image/jpeg";
height = 2;
id = 2X2;
width = 2;
Create extension of UIImageView
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
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) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
and Use like this
imageView.downloaded(from: "http://www.apple.com/euro/ios/ios8/a/generic/images/og.png")
I have been getting images from my API and in the past I have loaded them into a UIImage with the extension you will see below. However, now I am trying to get the images from the API and load them into UIButton image views. I don't know what to do to the extension and the other code to make it work. I appreciate the help!
Extension
Extension UIImageView {
func getURL2(url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
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),
httpURLResponse.url == url
else { return }
DispatchQueue.main.async() {
self.image = image
}
}.resume()
}
func downloadedFrom2(link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
getURL2(url: url, contentMode: mode)
}
}
Other code
func loadProfilePhoto(image: UIButton, link: String) {
image.downloadedFrom2(link: link)
image.imageView!.clipsToBounds = true
image.imageView!.layer.cornerRadius = (image.imageView!.frame.height) / 2
image.imageView!.contentMode = .scaleAspectFill
}
func loadRandom8() {
if self.users.count == 8 {
let completelink1 = users[0].picture_url
//ex. https://api.adorable.io/avatars/200/AngelicAlling.png
let completelink2 = users[1].picture_url
let completelink3 = users[2].picture_url
let completelink4 = users[3].picture_url
let completelink5 = users[4].picture_url
let completelink6 = users[5].picture_url
let completelink7 = users[6].picture_url
let completelink8 = users[7].picture_url
loadProfilePhoto(image: p2Image, link: completelink1)
loadProfilePhoto(image: p2Image, link: completelink2)
loadProfilePhoto(image: p3Image, link: completelink3)
loadProfilePhoto(image: p4Image, link: completelink4)
loadProfilePhoto(image: p5Image, link: completelink5)
loadProfilePhoto(image: p6Image, link: completelink6)
loadProfilePhoto(image: p7Image, link: completelink7)
loadProfilePhoto(image: p8Image, link: completelink8)
Your current extension is for UIImageView but you want to load the image in a UIButton, so change the extension to UIButton and make sure the button's type is set to Custom and not System. You can do this from the storyboard.
extension UIButton {
func getURL2(url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
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),
httpURLResponse.url == url
else { return }
DispatchQueue.main.async() {
self.setImage(image, for: .normal)
self.imageView?.contentMode = mode
}
}.resume()
}
public func downloadedFrom2(link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
getURL2(url: url, contentMode: mode)
}
}
If it didn't work for you read this
This is Question Video
I have a problem about imageView by using SDWebImage.
I change user's image and already get new user's image url, but when I push to this ViewController, it will show the old image first and change to new image.
What's wrong with me?
Thanks.
var avatar:String = "" // previous VC data pass to here
var photoImageView:UIImageView = { () -> UIImageView in
let ui = GeneratorImageView()
ui.backgroundColor = UIColor.clear
ui.layer.masksToBounds = true
ui.contentMode = .scaleAspectFill
return ui
}()
override func viewDidLoad() {
super.viewDidLoad()
iconImageFromUrl(imageView: iconImageView, url: avatar, isResize: false)
}
func iconImageFromUrl(imageView:UIImageView, url:String,isResize:Bool) {
imageView.setShowActivityIndicator(true)
imageView.setIndicatorStyle(.gray)
imageView.sd_setImage(with: URL(string:url), placeholderImage: nil, options: .lowPriority, progress: nil
, completed: { (image, error, cacheType, url) in
guard image != nil else{
imageView.image = resizeImage(image: #imageLiteral(resourceName: "defaultIcon"), newWidth: 50)
return
}
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
if data != nil
{
if let image = UIImage(data: data!)
{
DispatchQueue.main.async {
if isResize == true{
imageView.image = resizeImage(image: image, newWidth: 250)
}else{
imageView.image = image
}
}
}
}
}
})
}
sd_setImage method is written inside a category of UIImageView. After downloading the image it sets the image on UIImageview on its own and in the completion closure returns the downloaded/cached UIImage as well.
You dont need to create Data from imageUrl and set it again. If you want to resize image, you can do it on the returned image.
Also, you dont need to check the image nil for setting the default image, just pass the resized default image as placeholder image
imageView.sd_setImage(with: URL(string:url), placeholderImage: resizeImage(image: #imageLiteral(resourceName: "defaultIcon"), newWidth: 50), options: .lowPriority, progress: nil
, completed: { (image, error, cacheType, url) in
guard image != nil else {
return
}
if isResize {
imageView.image = resizeImage(image: image, newWidth: 250)
} })