viewForAnnotation混淆并迭代定制pinColor [英] viewForAnnotation confusion and customizing the pinColor iteratively
问题描述
目标是根据结构数组中存储的每个值自定义引脚颜色。
在这里,我实现了以下viewForAnnotation委托方法,并且有效伟大的基于我的结构数据数组的大小在循环中迭代地调用这个委托方法。因此,如果我想将所有引脚设置为一种颜色,例如紫色(这是下面代码中的注释行),它就可以工作。
问题是,当我根据数组中的值设置颜色时,它会通过此代码,但不会考虑任何案例值将它设置为备用颜色,一切都变为红色引脚(看似默认)。我打印出状态并进行调试,知道它已进入开关并相应地设置了pinColor,但它们似乎没有坚持。
func mapView(aMapView:MKMapView!,
viewForAnnotation批注:MKAnnotation!) - > MKAnnotationView! {
让theindex = mystructindex //从全局获取索引,如果注释是MKUserLocation,则使用
以下{
//返回nil所以map视图绘制标识用户位置的蓝点
返回nil
}
让reuseId =pin
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)为? MKPinAnnotationView
如果pinView == nil {
// println(Pinview为零)
pinView = MKPinAnnotationView(注释:annotation,reuseIdentifier:reuseId)
pinView !.canShowCallout = true
pinView!.animatesDrop = true
//预防性如果不让我的数组被调用超出我的数组索引值,因为代理被调用超出了for循环的一些未知原因
if(theindex< MySupplierData.count){
//根据MySupplierData结构数组中的状态值设置引脚颜色
切换MySupplierData [mystructindex ] .status {
case 0,1:
println(Case 0 or 1 - setting to Red)
pinView!.pinColor = .Red //需要帮助, show red pin
case 2:
println(Case 2 - Setting to Green)
pinView!.pinColor = .Green //好看
案例3:
println(案例3 - 设置为紫色)
pinView!.pinColor = .Purple //可以使用关注-up
默认值:
println(案例默认值 - 应该永远不会发生)
break;
} //结束开关
} //结束如果
// pinView!.pinColor = .Purple //没有开关就可以正常工作并尊重任何颜色我把它设置为。
}
else {
pinView!.annotation = annotation
}
return pinView
}
在ViewController中我的for循环中我按如下方式调用它,但是我没有对返回做任何事情。
//在此之前,我设置了一些标题和副标题,其工作正常
self.theMapView.addAnnotation(myAnnotation)
//调用我的mapview
mapView(theMapView,viewForAnnotation:myAnnotation)
我不做任何返回Pinview的东西 - 我认为我不需要,但是当使用开关代码时,所有的引脚都会被拉红。从根本上说,我必须在这里遗漏一些东西。
7-8-14更新以解决修改后的代码问题每个Anna的帮助很大/辅导。 TKS!
它几乎可以正常工作,地图中的所有引脚都有正确的颜色,但
立即显示之外的引脚有时是错误的。发布此处涉及的所有代码,因为它可以帮助其他人
,因为这似乎是关于如何在地图中进行自定义工作的一个非常常见的问题。
建议在自定义注释中保存其他变量的自定义类 - 在这种情况下,状态值来自我的数据结构MySupplierData。
class CustomMapPinAnnotation:NSObject,MKAnnotation {
var坐标:CLLocationCoordinate2D
var title:String
var subtitle:String
var status:Int
init(坐标:CLLocationCoordinate2D,title:String,subtitle:String,status:Int){
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.status = status
}
}
修改后的mapView - 现在使用传递给它的新CustomMapPinAnnotation:
func mapView(aMapView:MKMapView!,
viewForAnnotation批注:CustomMapPinAnnotation!) - > MKAnnotationView! {
让reuseId =pin
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)为? MKPinAnnotationView
如果pinView == nil {
// println(Pinview为零)
pinView = MKPinAnnotationView(注释:annotation,reuseIdentifier:reuseId)
pinView !.canShowCallout = true
pinView!.animatesDrop = true
//捕获我的自定义CustomMapPinAnnotation的代码,以便我们可以检查状态并设置颜色
if annotation.isKindOfClass( CustomMapPinAnnotation)
{
println(在mapView中找到我们的CustomMapPinAnnotation CLASS)
println(自定义标题= \(annotation.title))
println(自定义状态传递= \(annotation.status))
切换annotation.status {
case 0,1:
println(Case 0 or 1 - Setting to Red)
pinView!.pinColor = .Red
case 2:
println(Case 2 - Setting to Green)
pinView!.pinColor = .Green
case 3:
println(Case 3 - Setting to Purple)
pinView! .pinColor = .Purple
默认值:
println(Case default - Should Never Happen)
break;
} //切换
} //如果
}
else {
pinView!.annotation = annotation
}
return pinView
} // func mapView
在viewDidLoad中设置和For循环来设置注释
覆盖func viewDidLoad(){
super.viewDidLoad()
//设置区域和Span
var theSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta,longDelta)
//将区域设置为结构数组的第一个元素。
var theRegion:MKCoordinateRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(MySupplierData [0] .latitude,MySupplierData [0] .longitude),theSpan)
//这设置了地图类型(标准,卫星,混合)
self.theMapView.mapType = MKMapType.Standard
//现在循环结构数据从结构末端的1顶部开始映射数据
var mytitle:String =
var mysubtitle:String =
var myCustomPinAnnotation:CustomMapPinAnnotation
for mystructindex = 0; mystructindex< MySupplierData.count; ++ mystructindex {
println(INSIDE SUPPLIER LOOP INDEX = \(mystructindex))
切换MySupplierData [mystructindex] .status {
case 0:
mytitle =(Red)+ MySupplierData [mystructindex] .company
case 1:
mytitle =(Red)+ MySupplierData [mystructindex] .company
case 2:
mytitle =(Geeen)+ MySupplierData [mystructindex] .company
case 3:
mytitle =(Purple)+ MySupplierData [mystructindex] .company
默认值:
mytitle =?+ MySupplierData [mystructindex] .company
}
mysubtitle = MySupplierData [mystructindex] .subtitle
//使用我添加的状态创建自定义注释code
myCustomPinAnnotation = CustomMapPinAnnotation(
坐标:CLLocationCoordinate2DMake(MySupplierData [mystructindex] .latitude,MySupplierData [mystructindex] .longitude),
标题:mytitle,//自定义标题
副标题:mysubtitle,//自定义字幕
状态:MySupplierData [mystructindex] .status)//将驱动的状态pin颜色
//将此注释放在视图中。
self.theMapView.addAnnotation(myCustomPinAnnotation)
} //对于
//此行显示特定区域的显示,否则它似乎默认为美国地图。
self.theMapView.setRegion(theRegion,animated:true)
} // viewDidLoad
调试输出显示For循环执行完成按预期创建myCustomPinAnnotation,然后mapView中的自定义viewForAnnotation在内部执行
。当我将地图移动到直接视图之外的区域时,我注意到mapView中的viewForAnnotation会根据需要调用
并且我看到我的开关相应地执行但是引脚颜色并不总是正确的。初始显示图中的所有引脚每次都是正确的,所以
就是这些外部区域我目前所关注的是为什么它们关闭了。
首先,代码应 不 调用 viewForAnnotation
显式本身。
在 addAnnotation
行之后删除对 viewForAnnotation
的显式调用。 / p>
viewForAnnotation
是一种委托方法,地图视图会在需要时自动调用显示注释。如果没有自动调用,请确保设置了地图视图的委托
属性(例如, self
)。 / p>
第二(以及真正的问题),是代码假定 viewForAnnotation
委托方法只会在添加每个注释后立即调用一次。
情况并非如此,不能保证。只要需要显示注释,地图视图就会调用 viewForAnnotation
,并且可以多次为相同的注释调用,或者在实际添加注释后很长时间(例如,在用户平底锅之后)或缩放地图,注释进入视图)。
参见 MKAnnotationView是否缓冲其输入队列?以获取一些其他详细信息以及其他答案的相关链接,包括示例代码。
基本上,您必须使用注释对象本身存储影响注释视图的属性,并从传递到 viewForAnnotation $的
注释
参数中检索这些属性c $ c>。
我建议您使用的是:
我假设您使用的是内置注释类 MKPointAnnotation
。而不是使用 MKPointAnnotation
,它不允许您将自定义 status
属性与注释对象本身一起存储,或者:
-
创建一个实现
MKAnnotation
协议的自定义类,但也包含status
property。在创建注释时设置此属性,并从传递到viewForAnnotation
的注释
参数中提取其值,并设置<$ c因此,$ c> pinColor 。请参阅链接答案中的示例代码。 -
在
MySupplierData
中创建对象本身实现MKAnnotation
协议的对象。因此,如果MySupplierData
中的对象是某个类的实例,例如Supplier
,请设为Supplier
class符合MKAnnotation
协议,然后您可以添加MySupplierData
对象本身调用addAnnotation
时到地图视图。
The goal is to customize the pin colors per some values stored in an structure array.
Per some help here I implemented the the following viewForAnnotation delegate method and that works great calling this delegate method iteratively in a loop based on the size of my structure data array. So it works if I want to set all the pins to one color, purple for example (which is the commented line in the code below).
The problem is when I put in a switch to set the color based on a value in my array it goes through this code but does not respect any of the case values to set it to an alternate color and everything goes to a red pin (seemingly the default). I've printed out the status and debugged to know it is getting inside the switch and setting pinColor's accordingly but they don't seem to stick.
func mapView(aMapView: MKMapView!,
viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
let theindex = mystructindex // grab the index from a global to be used below
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
//println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
// Preventive if to keep this from being called beyond my arrays index value as the delegate getting called beyond the for loop for some unknown reason
if (theindex < MySupplierData.count) {
// Set the pin color based on the status value in MySupplierData structure array
switch MySupplierData[mystructindex].status {
case 0,1:
println("Case 0 or 1 - setting to Red")
pinView!.pinColor = .Red // Needs help, show red pin
case 2:
println("Case 2 - Setting to Green")
pinView!.pinColor = .Green // Looking Good
case 3:
println("Case 3 - Setting to Purple")
pinView!.pinColor = .Purple // Could use a follow-up
default:
println("Case default - Should Never Happen")
break;
} // end switch
} // end if
// pinView!.pinColor = .Purple // This works fine without the switch and respects any color I set it to.
}
else {
pinView!.annotation = annotation
}
return pinView
}
Inside my for loop within the ViewController I call this as follows, but I don't do anything with the return.
// previous to this I setup some Titles and Subtitle which work fine
self.theMapView.addAnnotation(myAnnotation)
// Call to my mapview
mapView(theMapView, viewForAnnotation: myAnnotation)
I don't do anything with the return Pinview - didn't think I needed to but all the pins get drawn red at this point when using the switch code. Fundamentally I must be missing something here.
7-8-14 Updates to address problems with revised code per Anna's great help/tutoring. TKS!
It almost works, All pins within the Map have the right colors but ones outside of the immediate display are sometimes wrong. Posting all the code involved here since it may help others as this seems to be a very common question on how to do custom work within Maps.
A custom class as suggested to hold other variable in a custom annotation - in this case the status value coming from my data structure, MySupplierData.
class CustomMapPinAnnotation : NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String
var subtitle: String
var status: Int
init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String, status: Int) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.status = status
}
}
The revised mapView - now utilizing the new CustomMapPinAnnotation being passed to it:
func mapView(aMapView: MKMapView!,
viewForAnnotation annotation: CustomMapPinAnnotation!) -> MKAnnotationView! {
let reuseId = "pin"
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
//println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
// Code to catch my custom CustomMapPinAnnotation so we can check the status and set the color
if annotation.isKindOfClass(CustomMapPinAnnotation)
{
println("FOUND OUR CustomMapPinAnnotation CLASS IN mapView")
println(" Custom Title = \(annotation.title)")
println(" Custom status passed = \(annotation.status)")
switch annotation.status {
case 0,1:
println("Case 0 or 1 - Setting to Red")
pinView!.pinColor = .Red
case 2:
println("Case 2 - Setting to Green")
pinView!.pinColor = .Green
case 3:
println("Case 3 - Setting to Purple")
pinView!.pinColor = .Purple
default:
println("Case default - Should Never Happen")
break;
} // switch
} // if
}
else {
pinView!.annotation = annotation
}
return pinView
} //func mapView
Within viewDidLoad the setup and For loop to setup the annotations
override func viewDidLoad() {
super.viewDidLoad()
// setup the region and Span
var theSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
// Set the region to the the first element of the structure array.
var theRegion:MKCoordinateRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(MySupplierData[0].latitude, MySupplierData[0].longitude), theSpan)
// This set the Map Type (Standard, Satellite, Hybrid)
self.theMapView.mapType = MKMapType.Standard
// Now loop through the structure data from 1 top the end of the structure to map the data
var mytitle: String = ""
var mysubtitle: String = ""
var myCustomPinAnnotation: CustomMapPinAnnotation
for mystructindex = 0; mystructindex < MySupplierData.count; ++mystructindex {
println("INSIDE SUPPLIER LOOP INDEX = \(mystructindex)" )
switch MySupplierData[mystructindex].status {
case 0:
mytitle = "(Red) " + MySupplierData[mystructindex].company
case 1:
mytitle = "(Red) " + MySupplierData[mystructindex].company
case 2:
mytitle = "(Geeen) " + MySupplierData[mystructindex].company
case 3:
mytitle = "(Purple) " + MySupplierData[mystructindex].company
default:
mytitle = "? " + MySupplierData[mystructindex].company
}
mysubtitle = MySupplierData[mystructindex].subtitle
// Create the Custom Annotations with my added status code
myCustomPinAnnotation = CustomMapPinAnnotation(
coordinate: CLLocationCoordinate2DMake(MySupplierData[mystructindex].latitude,MySupplierData[mystructindex].longitude),
title: mytitle, // custom title
subtitle: mysubtitle, // custom subtitle
status: MySupplierData[mystructindex].status) // status that will drive pin color
// put this annotation in the view.
self.theMapView.addAnnotation(myCustomPinAnnotation)
} // For
// This line brings up the display with the specific region in mind, otherwise it seems to default to a US Map.
self.theMapView.setRegion(theRegion, animated: true)
} // viewDidLoad
Debug output shows the For loop executes to completion as expected to create the myCustomPinAnnotation's before the custom viewForAnnotation in mapView gets executed on its own internally. As I move the map to areas outside the immediate view I do note the viewForAnnotation in mapView gets called as needed and I see my switch executing accordingly but the pin colors are not always correct. All the pins within the initial display map are correct every time so it's these outer region ones I am stuck on currently as to why they are off.
First, the code should not be calling viewForAnnotation
explicitly itself.
Remove the explicit call to viewForAnnotation
after the addAnnotation
line.
viewForAnnotation
is a delegate method and the map view will call it automatically when it needs to display an annotation. If it's not getting called automatically, make sure the map view's delegate
property is set (to self
for example).
Second (and the real issue), is that the code assumes that the viewForAnnotation
delegate method will get called only once and immediately after adding each annotation.
This is not the case and is not guaranteed. The map view will call viewForAnnotation
whenever it needs to display the annotation and could be called multiple times for the same annotation or long after the annotation is actually added (eg. after user pans or zooms the map and the annotation comes into view).
See does MKAnnotationView buffer its input queue? for some additional details and relevant links to other answers including sample code.
Basically, you must store the properties that affect an annotation's view with the annotation object itself and retrieve these properties from the annotation
parameter that is passed into viewForAnnotation
.
What I suggest for your case is this:
I assume you are using the built-in annotation class MKPointAnnotation
. Instead of using MKPointAnnotation
which does not let you store your custom status
property alongwith the annotation object itself, either:
Create a custom class that implements the
MKAnnotation
protocol but also with astatus
property. Set this property when creating the annotation and extract its value from theannotation
parameter passed intoviewForAnnotation
and set thepinColor
accordingly. See sample code in linked answer(s).Make the objects in the
MySupplierData
themselves objects that implement theMKAnnotation
protocol. So if the objects inMySupplierData
are instances of some class named, say,Supplier
, make theSupplier
class conform to theMKAnnotation
protocol and then you can add theMySupplierData
objects themselves to the map view when callingaddAnnotation
.
这篇关于viewForAnnotation混淆并迭代定制pinColor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!