Swift - Custom MKAnnotationView, set label title - ios

I am trying to customise the MKAnnotationView for my mapView callout bubbles. I am fine with setting the annotation title when the annotation is created, and also customising the MKAnnotationView to add labels or images e.t.c (in the viewForAnnotation delegate), but how do I change the label created in the viewForAnnotation delegate, so that the title of it is different for each pin?
The other issue I have is that if I don't add a title or subtitle to the annotation when it is created in the viewDidLoad method, but I still try and create one by leaving self.map.addAnnotation(annotation), when I run the app and tap the pin no callout bubble is displayed.
In the end I would like to have totally customised callout bubbles, with individual labels on them for each pin. So what i really ned to know is how to access the viewForAnnotation delegate when the annotation is created to change properties of it for each pin.
override func viewDidLoad() {
super.viewDidLoad()
var countries: [String] = ["Germany","Germany","Poland","Denmark"]
var practiceRoute: [CLLocationCoordinate2D] = [CLLocationCoordinate2DMake(50, 10),CLLocationCoordinate2DMake(52, 9),CLLocationCoordinate2DMake(53, 20),CLLocationCoordinate2DMake(56, 14)]
for vari=0; i<practiceRoute.count; i++ {
var annotation = MKPointAnnotation
annotation.title = countries[i]
annotation.coordinate = practiceRoute[i]
self.map.addAnnotation(annotation)
}
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if(pinView==nil){
pinView=MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
let base = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
base.backgroundColor = UIColor.lightGrayColor()
let label1 = UILabel(frame: CGRect(x: 30, y: 10, width: 60, height: 15))
label1.textColor = UIColor.blackColor()
label1.text = "12 photos"
base.addSubview(label1)
pinView!.leftCalloutAccessoryView = base
pinView!.pinColor = .Red
}
return pinView
}

Make your custom annotation view
There is no public API allowing you to access the label in the pop up directly. What you need to do is make a subclass of MKPinAnnotationView and do whatever customization you want there. As an example,
class CustomAnnotationView : MKPinAnnotationView
{
let selectedLabel:UILabel = UILabel.init(frame:CGRectMake(0, 0, 140, 38))
override func setSelected(selected: Bool, animated: Bool)
{
super.setSelected(false, animated: animated)
if(selected)
{
// Do customization, for example:
selectedLabel.text = "Hello World!!"
selectedLabel.textAlignment = .Center
selectedLabel.font = UIFont.init(name: "HelveticaBold", size: 15)
selectedLabel.backgroundColor = UIColor.lightGrayColor()
selectedLabel.layer.borderColor = UIColor.darkGrayColor().CGColor
selectedLabel.layer.borderWidth = 2
selectedLabel.layer.cornerRadius = 5
selectedLabel.layer.masksToBounds = true
selectedLabel.center.x = 0.5 * self.frame.size.width;
selectedLabel.center.y = -0.5 * selectedLabel.frame.height;
self.addSubview(selectedLabel)
}
else
{
selectedLabel.removeFromSuperview()
}
}
}
Other Notes
Use this custom view in the map view:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
var anno = mapView.dequeueReusableAnnotationViewWithIdentifier("Anno")
if anno == nil
{
anno = CustomAnnotationView.init(annotation: annotation, reuseIdentifier: "Anno")
}
return anno;
}
Since the title property of the annotation is not set, you will have to call the map view function selectAnnotation yourself. Add the following to the CustomAnnotationView class:
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
mapView?.selectAnnotation(self.annotation!, animated: true)
}
If you want to have more than one marker on the map:
Usually just draw the annotation simply during initialization. In setSelected just return false (meaning "show all annotations all the time").
class DotAnnotationView : MKPinAnnotationView {
let dot: UILabel = UILabel.init(frame:CGRect(x: 0, y: 0, width: 20, height: 20))
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
_setup()
}
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
_setup()
}
override func prepareForReuse() {
dot.text = "you forgot to set the text value?"
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(false, animated: animated)
}
func _setup() {
dot.textAlignment = .center
.. etc
}
}
You set the string (or other values - say color of the panel) for each annotation in mapView#viewFor. It's like populating a cell in a UITableView.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let textForThisItem = annotation.title!!
// or, just use index#of to determine which row this is in your data array
if annotation.isEqual(mkMap.userLocation) {
// skip the user-position indicator
return nil
}
var anno = mapView.dequeueReusableAnnotationView(withIdentifier: "anno")
if anno == nil {
anno = DotAnnotationView.init(annotation: annotation, reuseIdentifier: "anno")
}
(anno as! DotAnnotationView).dot.text = textForThisItem
return anno
}
Finally note that somewhat confusingly, if you very simply change the class of CustomAnnotationView from MKPinAnnotationView to MKAnnotationView, everything works the same but it replaces "all of the pin" rather than just the annotation.

Updated the code for the latest swift.
This is the new subclass of MKPinAnnotationView which you can copy paste to test:
import UIKit
import MapKit
class CustomAnnotationView : MKPinAnnotationView
{
let selectedLabel:UILabel = UILabel.init(frame:CGRect(x:0, y:0, width:140, height:38))
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(false, animated: animated)
if(selected)
{
// Do customization, for example:
selectedLabel.text = "Hello World!!"
selectedLabel.textAlignment = .center
selectedLabel.font = UIFont.init(name: "HelveticaBold", size: 15)
selectedLabel.backgroundColor = UIColor.gray
selectedLabel.layer.borderColor = UIColor.darkGray.cgColor
selectedLabel.layer.borderWidth = 2
selectedLabel.layer.cornerRadius = 5
selectedLabel.layer.masksToBounds = true
selectedLabel.center.x = 0.5 * self.frame.size.width;
selectedLabel.center.y = -0.5 * selectedLabel.frame.height;
self.addSubview(selectedLabel)
}
else
{
selectedLabel.removeFromSuperview()
}
}
}

Related

Name under custom annotation views

I have a custom annotation view, when I click on any annotation point, I can see the custom view with all information. but what I need is to see name of each industrial parks under each annotation points. now I can see only point but without names
I need to see name under points.
//MARK: MKMapViewDelegate
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation
{
return nil
}
var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: "Pin")
if annotationView == nil{
annotationView = AnnotationView(annotation: annotation, reuseIdentifier: "Pin")
annotationView?.canShowCallout = false
}else{
annotationView?.annotation = annotation
}
annotationView?.image = UIImage(named: "test3a")
return annotationView
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView)
{
// 1
if view.annotation is MKUserLocation
{
// Don't proceed with custom callout
return
}
// 2
let starbucksAnnotation = view.annotation as! StarbucksAnnotation
let views = Bundle.main.loadNibNamed("CustomCalloutView", owner: nil, options: nil)
let calloutView = views?[0] as! CustomCalloutView
calloutView.starbucksName.text = starbucksAnnotation.name
calloutView.starbucksAddress.text = starbucksAnnotation.address
calloutView.starbucksPhone.text = starbucksAnnotation.phone
//
let button = UIButton(frame: calloutView.starbucksPhone.frame)
button.addTarget(self, action: #selector(CellViewController.callPhoneNumber(sender:)), for: .touchUpInside)
calloutView.addSubview(button)
calloutView.starbucksImage.image = starbucksAnnotation.image
// 3
calloutView.center = CGPoint(x: view.bounds.size.width / 2, y: -calloutView.bounds.size.height*0.52)
view.addSubview(calloutView)
mapView.setCenter((view.annotation?.coordinate)!, animated: true)
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
if view.isKind(of: AnnotationView.self)
{
for subview in view.subviews
{
subview.removeFromSuperview()
}
}
}
If your goal is to have a label under the annotation, just have your custom annotation add this subview (and have it observe changes to the title so that it can update the label).
For example:
class AnnotationView: MKAnnotationView {
static var image: UIImage = ...
private var titleObserver: NSObjectProtocol!
private let titleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.backgroundColor = UIColor.black.withAlphaComponent(0.25)
label.font = UIFont.preferredFont(forTextStyle: .caption1)
return label
}()
override var annotation: MKAnnotation? {
didSet { updateForNewAnnotation() }
}
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
image = Self.image
centerOffset = CGPoint(x: 0, y: -Self.image.size.height / 2)
configureTitleView()
updateForNewAnnotation()
}
func configureTitleView() {
addSubview(titleLabel)
NSLayoutConstraint.activate([
titleLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
titleLabel.topAnchor.constraint(equalTo: bottomAnchor)
])
clipsToBounds = false
}
func updateForNewAnnotation() {
guard let annotation = annotation as? MKPointAnnotation else { // replace `MKPointAnnotation` with whatever class your annotations are
titleObserver = nil
titleLabel.text = nil
return
}
titleLabel.text = annotation.title
titleObserver = annotation.observe(\.title) { [weak self] annotation, _ in
self?.titleLabel.text = annotation.title
}
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
That yields:
Obviously, feel free to configure your label however you want, but this illustrates the basic idea of adding subview and observing changes on the annotation’s title.
As an aside, notice that I set the image inside the AnnotationView class. If you keep all configuration inside the AnnotationView class, not only is it a better separation of responsibilities, but you can then retire mapView(_:viewFor:) entirely, and replace it with a single line inside your viewDidLoad that registers the annotation view class with register(_:forAnnotationViewWithReuseIdentifier:):
mapView.register(AnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)

Swift - Custom UIView for MKAnnotationView map pin

How can I set a custom view for MKAnnotationView? I want my map pins to look unique via a UIView. That UIView subclass could have other views in it I want to customize.
There are many examples online on how to set the annotations image, but not how to actually change that annotation:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView?
{
if !(annotation is MKPointAnnotation) {
return nil
}
let annotationIdentifier = "AnnotationIdentifier"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView!.canShowCallout = true
}
else {
annotationView!.annotation = annotation
}
let pinImage = UIImage(named: "customPinImage")
annotationView!.image = pinImage
return annotationView
}
MKAnnotationView is a subclass of UIView that can be subclassed itself.
So you would just need to subclass MKAnnotationView.
Custom Subview
Here a simple example that shows a blue triangle. Since you mentioned that the UIView custom subclass should have other views in it I added a label that should show a number.
class CustomAnnotationView: MKAnnotationView {
private let annotationFrame = CGRect(x: 0, y: 0, width: 40, height: 40)
private let label: UILabel
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
self.label = UILabel(frame: annotationFrame.offsetBy(dx: 0, dy: -6))
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
self.frame = annotationFrame
self.label.font = UIFont.systemFont(ofSize: 24, weight: .semibold)
self.label.textColor = .white
self.label.textAlignment = .center
self.backgroundColor = .clear
self.addSubview(label)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) not implemented!")
}
public var number: UInt32 = 0 {
didSet {
self.label.text = String(number)
}
}
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
context.beginPath()
context.move(to: CGPoint(x: rect.midX, y: rect.maxY))
context.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
context.addLine(to: CGPoint(x: rect.minX, y: rect.minY))
context.closePath()
UIColor.blue.set()
context.fillPath()
}
}
MKMapViewDelegate method
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard annotation is MKPointAnnotation else { return nil }
let customAnnotationView = self.customAnnotationView(in: mapView, for: annotation)
customAnnotationView.number = arc4random_uniform(10)
return customAnnotationView
}
Custom Annoation View
private func customAnnotationView(in mapView: MKMapView, for annotation: MKAnnotation) -> CustomAnnotationView {
let identifier = "CustomAnnotationViewID"
if let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? CustomAnnotationView {
annotationView.annotation = annotation
return annotationView
} else {
let customAnnotationView = CustomAnnotationView(annotation: annotation, reuseIdentifier: identifier)
customAnnotationView.canShowCallout = true
return customAnnotationView
}
}
Result
The result would look like this:
I previously used a UIView to annotate a MKAnnotationView. I did this by adding a the view as a subview to the MKAnnotationView but soon found out that this caused a whole load of memory issues when rendering a lot of annotations on my map. Instead I reverted to building a UIView comprised of my different subviews and then converting it into a UIImage and assigning it to the image property of MKAnnotationView.
Here is a link to a Stack Overflow answer that will help with the UIView to UIImage conversion.

Trouble creating custom MKAnnotationView

I'm having a hard time displaying a custom annotation view. Specifically, I'm trying to set an image named "pin" to be the new map pin. The default pin always shows. I've been making small changes for a few hours to no avail, such as changing "pin" to "pin.png" and altering the structure of the mapView:viewFor method. Here's what I have. Could you please take a look and see if anything stands out?
Thanks for any help!
Annotation Class:
class Annotation: NSObject, MKAnnotation {
dynamic var coordinate : CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(location coord:CLLocationCoordinate2D) {
self.coordinate = coord
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
AnnotationView Class:
class AnnotationView : MKAnnotationView {
override init(annotation:MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation,
reuseIdentifier: reuseIdentifier)
let im = UIImage(named: "pin")!
self.frame = CGRect(x: 0, y: 0, width: im.size.width / 3.0 + 5, height: im.size.height / 3.0 + 5)
self.centerOffset = CGPoint(x: 0, y: -20)
self.isOpaque = false
}
required init (coder: NSCoder) {
fatalError("NSCoding not supported")
}
override func draw(_ rect: CGRect) {
let im = UIImage(named: "pin")!
im.draw(in: self.bounds.insetBy(dx: 5, dy: 5))
}
}
mapView:viewFor: Method:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var v : MKAnnotationView! = nil
let ident = "pin"
v = mapView.dequeueReusableAnnotationView(withIdentifier: ident)
if v == nil {
v = AnnotationView(annotation: annotation, reuseIdentifier: ident)
v.canShowCallout = true
}
v.annotation = annotation
return v
}
Other Relevant Methods:
#IBAction func submitDog(_ sender: Any) {
let newDog = Dog(name: newDogName.text!, score: 11, picture: image!, location: location!)
dogs.append(newDog)
print(dogs.last!)
UIView.animate(withDuration: 0.5, animations: {
}) { _ in
self.newDogView.animation = "slideUp"
self.newDogView.animate()
self.newDogView.isHidden = true
self.newDogName.text = ""
self.map.isUserInteractionEnabled = true
}
dropNewPin(locatedAt: dogs.last!.location, name: dogs.last!.name, rate: dogs.last!.score)
}
func dropNewPin(locatedAt: CLLocation, name: String, rate: Int) {
let annotation = Annotation(location: CLLocationCoordinate2D(latitude: locatedAt.coordinate.latitude, longitude: locatedAt.coordinate.longitude))
annotation.title = name
annotation.subtitle = "\(rate)/10"
self.map.addAnnotation(annotation)
}
First you need add your viewController as delegate of your map
self.mapView.delegate = self
After that I recommend you use the MKAnnotationView instead of modify and add the image with custom drawing, if you need a custom Annotation view then you need to add a xib file and your custom class as file owner and make the proper adjustments
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
//to avoid make a custom Annotation view for your user location
if(annotation is MKUserLocation){
return nil
}
let ident = "pin"
var v = mapView.dequeueReusableAnnotationView(withIdentifier: ident)
if v == nil {
v = MKAnnotationView(annotation: annotation, reuseIdentifier: ident)
v?.image = UIImage(named: "pin")
v?.canShowCallout = true
}
v?.annotation = annotation
return v
}

Custom Annotation View Callout Not Showing

I have made a custom annotation and custom annotation views but for some reason the callouts are not showing.
class MyAnnotation: NSObject,MKAnnotation {
var coordinate :CLLocationCoordinate2D
var title :String?
var subtitle: String?
init(coordinate :CLLocationCoordinate2D, title :String?, subtitle :String?) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
}
}
Annotation View
class MyAnnotationView: MKAnnotationView {
override init(frame: CGRect) {
super.init(frame: frame)
}
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
setup()
}
func setup() {
self.canShowCallout = true
let logo = UIImage(named: "logo.png")
let size = CGSize(width: 100, height: 100)
UIGraphicsBeginImageContext(size)
logo?.drawInRect(CGRectMake(0, 0, size.width, size.height))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let logoImageView = UIImageView(image: resizedImage)
logoImageView.userInteractionEnabled = true
self.addSubview(logoImageView)
}
Populating Annotations
private func populateAnnotations() {
for location in self.locations {
let annotation = MyAnnotation(coordinate: CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude), title: location.name, subtitle: "nothing")
self.mapView.addAnnotation(annotation)
}
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let annotationView = MyAnnotationView(annotation: annotation, reuseIdentifier: "AnnotationView")
return annotationView
}
When I click on the custom annotation it does not show a callout.

swift custom map class

I am learning Swift and want to create a subclass of MKMapKit to encapsulate some specific functionality, like checking distance between two points and creating custom annotations and separate all the map code into one class.
I have created a class:
class GameMapViewController: MKMapView, MKMapViewDelegate{...}
I initiate the class in code in the main view controller (and adding it as a subview to a view on the storyboard so I can control where it is more easily):
gameMap = GameMapViewController(container: mapViewHolder)
which sets everything up ok and all works EXCEPT for when I want to trigger a segue from a custom annotation:
func mapView(mapView: MKMapView!, didSelectAnnotationView view: MKAnnotationView!) {...}
The didSelectAnnotationView gets called when I tap on an annotation callout but nothing has the method performSegueWithIdentifier that I am looking for, that all the solutions to similar questions suggest I should be using....
(I have tried putting a MapKit View onto the storyboard and changing its class to use GameMapViewController but none of the init functions get fired)
I am guessing its something to with how I am initialising my custom class?
MainViewController.swift:
override func viewDidLoad() {
super.viewDidLoad()
....
// Create the game map
gameMap = GameMapViewController(container: mapViewHolder)
mapViewHolder.addSubview(gameMap)
...
}
GameMapViewController.swift:
import UIKit
import MapKit
class GameMapViewController: MKMapView, MKMapViewDelegate{
var spanQuestion:MKCoordinateSpan = MKCoordinateSpanMake(180, 180)
var spanAnswer:MKCoordinateSpan = MKCoordinateSpanMake(180, 180)
var hasUserCityLocationGuess: Bool = false
var containingView: UIView
override init(){
println ("GameMapViewController init")
containingView = UIView()
super.init(frame: CGRect(x: 0, y: 0, width: 1000, height: 1000))
self.delegate=self
var latDeltaAnswer:CLLocationDegrees = 50
var lngDeltaAnswer:CLLocationDegrees = 50
spanAnswer = MKCoordinateSpanMake(latDeltaAnswer, lngDeltaAnswer)
var latDeltaQuestion:CLLocationDegrees = 180
var lngDeltaQuestion:CLLocationDegrees = 180
spanQuestion = MKCoordinateSpanMake(latDeltaQuestion, lngDeltaQuestion)
}
required init(coder aDecoder: NSCoder) {
containingView = UIView()
super.init(coder: aDecoder)
self.delegate = nil
println ("GameMapViewController init with decoder")
}
convenience init(container: UIView) {
println ("GameMapViewController convenience")
self.init()
self.delegate = self
containingView = container
}
func mapViewDidFinishLoadingMap(mapView: MKMapView!) {
println("mapViewDidFinishLoadingMap")
}
func mapViewWillStartLoadingMap(mapView: MKMapView!) {
self.frame = CGRect (x: 0, y: 0, width: containingView.frame.width, height: containingView.frame.height)
self.contentMode = UIViewContentMode.ScaleAspectFill
superview?.sizeToFit()
var guessPlaceRecognizer = UILongPressGestureRecognizer(target: self, action: "guessPlace:")
guessPlaceRecognizer.minimumPressDuration = 1.0
mapView.addGestureRecognizer(guessPlaceRecognizer)
mapView.mapType = MKMapType.Satellite
}
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
if overlay is MKCircle {
var circleRenderer = MKCircleRenderer(overlay: overlay)
circleRenderer.strokeColor = UIColor.redColor()
circleRenderer.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.1)
circleRenderer.lineWidth = 1
//userOverlayCircleRender = circleRenderer
return circleRenderer
} else {
return nil
}
}
func guessPlace(gestureRecognizer:UIGestureRecognizer){
let guessPlaceFirst = NSUserDefaults.standardUserDefaults().boolForKey("guess_place_preference")
if guessPlaceFirst {
var touchPoint = gestureRecognizer.locationInView(self)
var newCoord:CLLocationCoordinate2D = self.convertPoint(touchPoint, toCoordinateFromView: self)
var userAnnotation = UserPointAnnotation()
userAnnotation.coordinate = newCoord
self.addAnnotation(userAnnotation)
var getLat: CLLocationDegrees = newCoord.latitude
var getLon: CLLocationDegrees = newCoord.longitude
var circleCenter: CLLocation = CLLocation(latitude: getLat, longitude: getLon)
addRadiusCircle(circleCenter)
hasUserCityLocationGuess = true
}
}
func showCity() {
let location = CLLocationCoordinate2D(latitude: (currentCity["latitude"]! as CLLocationDegrees), longitude: (currentCity["longitude"]! as CLLocationDegrees))
let region:MKCoordinateRegion = MKCoordinateRegionMake(location, self.spanAnswer)
let city: String = currentCity["city"]! as String
let conditions: String = currentCity["description"] as String
let country: String = currentCity["country"]! as String
let address = "\(city), \(country)"
let cityAnnotation = CityPointAnnotation()
cityAnnotation.title = address
cityAnnotation.subtitle = "\(conditions)"
cityAnnotation.coordinate = location
self.setRegion(region, animated: true)
self.addAnnotation(cityAnnotation)
self.selectAnnotation(cityAnnotation, animated: true)
}
func cityInfoClick(sender:UIButton){
//sender.performSegueWithIdentifier("segueCityWebView")
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
// Handle any custom annotations.
if annotation is CityPointAnnotation {
// Try to dequeue an existing pin view first.
let reuseId = "CityPointAnnotationView"
var annotationView = self.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
annotationView.image = UIImage(named: "marker.png")
annotationView.rightCalloutAccessoryView = UIButton.buttonWithType(.InfoDark) as UIButton
annotationView.canShowCallout = true
return annotationView;
} else {
annotationView.annotation = annotation
}
return annotationView
}
return nil;
}
func mapView(mapView: MKMapView!, didSelectAnnotationView view: MKAnnotationView!) {
println("didSelectAnnotationView")
}
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
println("calloutAccessoryControlTapped1")
///////////////////
// I want to do a segue here
// but nothing has the method performSegueWithIdentifier (self, mapView, control....)
///////////////////
}
func resetMap(){
self.removeAnnotations(self.annotations)
self.removeOverlays(self.overlays)
var region:MKCoordinateRegion = MKCoordinateRegionMake(self.centerCoordinate, spanQuestion)
self.setRegion(region, animated: true)
hasUserCityLocationGuess = false
}
func addRadiusCircle(location: CLLocation){
var radius = NSUserDefaults.standardUserDefaults().doubleForKey("guess_place_radius") as CLLocationDistance
var circle = MKCircle(centerCoordinate: location.coordinate, radius: radius )
self.removeOverlays(self.overlays)
self.addOverlay(circle)
}
func doGeoCode( cityObject:PFObject ) -> Bool {
....
}
func userCityLocationGuess(userGuessTemp:Int)->NSDictionary {
....
}
}
It's because you're confusing views and view controllers. You have a view (subclass of MKMapView, but you're naming it and trying to use it as a controller. It is also doings the job of a controller.
So, you should really have a view controller which owns and configures a map view (plain MKMapView), and then it can interact with segues.

Resources