我对mapkit有点陌生,但我想知道,我能为地图上的每一个别针设置不同的图像吗?例如,字典中有用户信息,而不是普通的引脚图像,必须有他们自己的图像。如何为以下输出设置viewFor注释方法。
[{
email = "user1@gmail.com";
id = jqvDgcBoV9Y4sx1BHCmir5k90dr1;
name = User1;
profileImageUrl = "<null>";
}, {
email = "user2@gmail.com";
id = bqvDmcBoV9Y4sx1BqCmirnk90drz;
name = User2;
profileImageUrl = "https://firebasestorage.googleapis.com/v0/";
}, {
email = "user3@gmail.com";
id = axmDgcB5V9m4sx1nHC5ir5kn1dn3;
name = User3;
profileImageUrl = "https://firebasestorage.googleapis.com/v0/";
}]
顺便说一句,我有一个函数可以将UIImageView转换成UIImage,但不是UIImage,这是我最大的困难之一。
现在我的viewForAnnotation代表。
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var annotationView: MKAnnotationView?
var annotationViewx: MKAnnotationView?
let annotationIdentifier = "AnnotationIdentifier"
guard !annotation.isKind(of: MKUserLocation.self) else {
var annotationViewq: MKAnnotationView?
annotationViewq = MKAnnotationView(annotation: annotation, reuseIdentifier: "userLocation")
annotationViewq?.image = UIImage(named: "myLocation.png")
let size = CGSize(width: 17, height: 17)
UIGraphicsBeginImageContext(size)
annotationViewq?.image!.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
annotationViewq?.image = resizedImage
annotationViewq?.isEnabled = true
annotationViewq?.isUserInteractionEnabled = true
return annotationViewq
}
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) {
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
annotationView?.canShowCallout = true
annotationView?.image = UIImage(named: "emptyPhoto.png")
let size = CGSize(width: 17, height: 17)
UIGraphicsBeginImageContext(size)
annotationView?.image!.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
annotationView?.image = resizedImage
return annotationView
}
//This annotation not working. but not problem
let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
av.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
annotationViewx?.canShowCallout = true
annotationViewx?.image = UIImage(named: "trafficIcon.png")
let size = CGSize(width: 17, height: 17)
UIGraphicsBeginImageContext(size)
annotationViewx?.image!.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
annotationViewx?.image = resizedImage
annotationViewx = av
return annotationViewx
}
发布于 2017-01-04 22:44:24
首先,让我说,我认为matt已经找到了问题的根源,即如果您有带有自己的图像的注释,您应该定义自己的注释类型来捕获图像的URL。
class CustomAnnotation: NSObject, MKAnnotation {
dynamic var coordinate: CLLocationCoordinate2D
dynamic var title: String?
dynamic var subtitle: String?
var imageURL: URL?
init(coordinate: CLLocationCoordinate2D, title: String? = nil, subtitle: String? = nil, imageURL: URL? = nil) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.imageURL = imageURL
super.init()
}
}
当您添加注释时,请确保提供URL,这样您就可以开始比赛了。我要指出的另一件事是,您确实希望跟踪哪个网络请求与哪个注释相关联(以便在需要时可以取消它)。因此,我将向注释视图类添加一个URLSessionTask
属性:
class CustomAnnotationView: MKAnnotationView {
weak var task: URLSessionTask? // keep track of this in case we need to cancel it when the annotation view is re-used
}
坦率地说,我会将所有复杂的配置代码从mapView(_:viewFor:)
方法中提取出来,并将其放入注释视图类中,以便更好地分工,避免视图控制器膨胀。
因此,例如,MKUserLocation
注释的自定义注释视图:
class CustomUserAnnotationView: MKAnnotationView {
static let reuseIdentifier = Bundle.main.bundleIdentifier! + ".customUserAnnotationView"
private let size = CGSize(width: 17, height: 17)
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
image = UIImage(named: "myLocation.png")?.resized(to: size)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
另一个用于具有CustomAnnotation
属性的imageURL
注释,它将异步获取所需的映像:
class CustomAnnotationView: MKAnnotationView {
static let reuseIdentifier = Bundle.main.bundleIdentifier! + ".customAnnotationView"
private weak var task: URLSessionTask?
private let size = CGSize(width: 17, height: 17)
override var annotation: MKAnnotation? {
didSet {
if annotation === oldValue { return }
task?.cancel()
image = UIImage(named: "emptyPhoto.png")?.resized(to: size)
updateImage(for: annotation)
}
}
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
canShowCallout = true
rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
image = UIImage(named: "emptyPhoto.png")?.resized(to: size)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func updateImage(for annotation: MKAnnotation?) {
guard let annotation = annotation as? CustomAnnotation, let url = annotation.imageURL else { return }
let task = URLSession.shared.dataTask(with: url) { data, _, error in
guard let data = data,
let image = UIImage(data: data)?.resized(to: self.size),
error == nil else {
print(error ?? "Unknown error")
return
}
DispatchQueue.main.async {
UIView.transition(with: self, duration: 0.2, options: .transitionCrossDissolve, animations: {
self.image = image
}, completion: nil)
}
}
task.resume()
self.task = task
}
}
然后,在iOS 11和更高版本中,我的视图控制器可以简单地在viewDidLoad
中注册这两个类。
mapView.register(CustomUserAnnotationView.self, forAnnotationViewWithReuseIdentifier: CustomUserAnnotationView.reuseIdentifier)
mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: CustomAnnotationView.reuseIdentifier)
然后,mapView(_:viewFor:)
蒸馏到一个简单得多的方法:
extension ViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier: String
switch annotation {
case is MKUserLocation: identifier = CustomUserAnnotationView.reuseIdentifier
case is CustomAnnotation: identifier = CustomAnnotationView.reuseIdentifier
default: return nil
}
return mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: annotation)
}
}
注意,我试图修复隐藏在您的viewForAnnotation
方法中的大量其他问题,特别是:
UIGraphicsEndImageContext
。因此,我建议删除它(例如,在这个UIImage
扩展中),并可能使用UIGraphicsImageRenderer
来简化它:
扩展UIImage { func调整大小(大小: CGSize) -> UIImage {返回UIGraphicsImageRenderer(大小:大小).image{_ in绘图(in:CGRect(原产地:.zero,size: size)}
您可能需要考虑是否需要方面填充或类似的内容,但是这里有一些其他的想法:https://stackoverflow.com/a/28513086/1271826。或者,也许更好的是,看看AlamofireImage或翠鸟的调整例程。
但是,带回家的信息是,您应该将血淋淋的调整逻辑从viewForAnnotation
中提取出来,放到它自己的例程/库中。URLSession.shared.dataTask
,而不需要寻找缓存等等。您显然可以在这里变得更加复杂(例如缓存大小调整的图像视图等等)。is
测试。例如:
如果注释是MKUserLocation {.}
这在很大程度上是一样的,但更直观一些。image
属性使用了一个调整大小的占位符图像。为了将来的读者,让我说这一点很重要,因为标准注释视图不能很好地处理image
大小的异步更改。您可以修改该类这样做,或者使用标准大小的占位符图像,更容易,就像这里一样。注意,请参阅本答案的事先修订 for iOS 10.x和更早版本。
发布于 2017-01-04 17:12:23
但是我想知道,我能给地图上的每一个别针设置不同的图像吗?
当然。您需要创建一个自定义注释类型。您的自定义批注类型将在要给它的实例属性中携带图像信息。这样,当您到达mapView(_:viewFor:)
时,您将知道这个注释需要什么图像,并且可以分配它。
示例:
class MyAnnotation : NSObject, MKAnnotation {
dynamic var coordinate : CLLocationCoordinate2D
var title: String?
var subtitle: String?
var imageName: String?
init(location coord:CLLocationCoordinate2D) {
self.coordinate = coord
super.init()
}
}
在创建注释时,在将注释附加到映射之前,也要分配给它的imageName
。现在,映射调用请求图像视图的委托,您可以读取imageName
属性,您将知道该做什么。
https://stackoverflow.com/questions/41469459
复制相似问题