I'm very new to iphone development and I'm trying to annotate a map. I've been able to get 3 location points on a map with hardcoded coordinates and now I'm trying to customize the pins. I know to do that you need to implement the:-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation { delegate method.
For some reason I've been unable to even get it called. Here is what I have in the controller header:
#import "ArtPiece.h"
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface TestViewController : UIViewController <MKMapViewDelegate> {
MKMapView *mapView;
NSMutableArray *mapAnnotations;
float results_lat[3];
float results_long[3];
NSMutableArray *results_title;
NSMutableArray *Arts;
}
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property (nonatomic, retain) NSMutableArray *mapAnnotations;
#end
And here is what I have in the controller implementation:
- (void)viewDidLoad {
results_long[0] = -122.477989;
results_lat[0] = 37.810000;
results_long[1] = -122.480000;
results_lat[1] = 37.820000;
results_long[2] = -122.4850000;
results_lat[2] = 37.830000;
self.mapAnnotations = [[NSMutableArray alloc] initWithCapacity:3];
Arts = [[NSMutableArray alloc] initWithCapacity:3];
for(int x = 0; x<3; x++)
{
// creates an ArtPiece object and sets its lat and long
ArtPiece *a = [[ArtPiece alloc] init];
a.longitude = [NSNumber numberWithDouble:results_long[x]];
a.latitude = [NSNumber numberWithDouble:results_lat[x]];
a.title = #"please show up";
// add objects to annotation array
[self.mapAnnotations insertObject:a atIndex:x];
[a release];
}
// center screen on cali area
[self gotoLocation];
for(int x = 0; x<3; x++)
{
[mapView addAnnotations:mapAnnotations];
}
}
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation {
NSLog(#"This is not printing to to console...");
MKPinAnnotationView *pinView = nil;
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil ) pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinView.pinColor = MKPinAnnotationColorPurple;
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
}
else {
[mapView.userLocation setTitle:#"I am here"];
}
return pinView;
}
And here is the ArtPiece class implementation:
#import "TestViewController.h"
#import "ArtPiece.h"
#import <MapKit/MapKit.h>
#import <CoreData/CoreData.h>
#implementation ArtPiece
#synthesize title, artist, series, description, latitude, longitude;
- (CLLocationCoordinate2D)coordinate
{
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = [self.latitude doubleValue];
theCoordinate.longitude = [self.longitude doubleValue];
return theCoordinate;
}
#end
It's probably something simple. Is there something wrong with my method declaration? Did I declare the delegate wrong? I can't figure it out, again, I'm very new to this objective c/delegate stuff. Thanks for any help.
The addAnnotations method expects an NSArray of objects that conform to the MKAnnotation protocol.
You are adding objects of type ArtPiece which don't seem to implement MKAnnotation which has a coordinate property (not latitude and longitude properties).
Update your ArtPiece class to conform to MKAnnotation (or use the pre-defined MKPointAnnotation class). But updating your custom class is a better fix.
Related
When I try to drag the pin, it does not move. When I touch it, it darkens. However, it never lifts up, and it never moves around.
Here is the header file for my annotation class:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <Parse/Parse.h>
#interface GeoPointAnnotation : NSObject <MKAnnotation>
- (id)initWithObject:(PFObject *)aObject;
#property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly, copy) NSString *title;
#property (nonatomic, readonly, copy) NSString *subtitle;
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate;
#end
Here's where I create the annotation in my view controller:
- (void)updateMap
{
[self.mapView removeAnnotations:self.mapView.annotations];
PFGeoPoint *geoPoint = [self.post location];
// center the map around the geopoint
[self.mapView setRegion:MKCoordinateRegionMake(
CLLocationCoordinate2DMake(geoPoint.latitude, geoPoint.longitude),
MKCoordinateSpanMake(0.01, 0.01)
)];
GeoPointAnnotation *annotation = [[GeoPointAnnotation alloc] initWithObject:self.post.object];
[self.mapView addAnnotation:annotation];
}
// from Geolocations by Parse
#pragma mark - MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
static NSString *GeoPointAnnotationIdentifier = #"RedPin";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:GeoPointAnnotationIdentifier];
if (!annotationView) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:GeoPointAnnotationIdentifier];
annotationView.pinColor = MKPinAnnotationColorRed;
annotationView.canShowCallout = YES;
annotationView.draggable = YES;
annotationView.animatesDrop = YES;
}
return annotationView;
}
Any ideas?
Found the problem: I forgot to hook up the Map View's delegate in my Storyboard xib. h/t Nitin Gohel - thanks!
I have 3 types of locations.
I'm getting the data from my server, then I'm parsing it and displaying the locations on the mapView.
I want to display different colors for the different types of data. 3 types = 3 colors.
How can I control this?
Implement the viewForAnnotation delegate method for doing this.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[yourAnnotationLocation class]])
{
MKAnnotationView *annotationView = (MKAnnotationView *) [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
//if you need image you can set it like
//annotationView.image = [UIImage imageNamed:#"yourImage.png"];//here we use a nice image instead of the default pins
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
annotationView.annotation = annotation;
}
if ([annotation.title isEqualToString:#"Midhun"])
{
annotationView.pinColor = MKPinAnnotationColorGreen;
}
else
{
annotationView.pinColor = MKPinAnnotationColorRed;
}
return annotationView;
}
return nil;
}
For setting custom property to your annotation add a class which confirms to MKAnnotation protocol.
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyLocation : NSObject <MKAnnotation> {
NSString *_name;
NSString *_address;
int _yourValue;
CLLocationCoordinate2D _coordinate;
}
#property (copy) NSString *name;
#property (copy) NSString *address;
#property (assign) yourValue;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithName:(NSString*)name address:(NSString*)address coordinate:(CLLocationCoordinate2D)coordinate;
#end
This is is a nice tutorial.
Try this,
annotation1.subtitle = #"1st annotation";
annotation2.subtitle = #"2st annotation";
annotation3.subtitle = #"3st annotation";
Check annotation
if ([annotation.subtitle isEqualToString:#"1st annotation"])
{
//change color
}
else if ([annotation.subtitle isEqualToString:#"2st annotation"])
{
//change color
}
else if ([annotation.subtitle isEqualToString:#"3st annotation"])
{
//change color
}
You can do something with latitude and longitude comparison
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { static NSString *identifier = #"yourIdentifier";
MKPinAnnotationView *pin = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if([annotation coordinate].latitude==YourLocationLatitude)
{
pin.image=[UIImage imageNamed:#"Flag-red.png"];
}
else
{
pin.image=[UIImage imageNamed:#"Flag-green.png"];
}}
I am a new-be in Objective C. Here I want to ask a simple question.
I have created a view controller in storyboard, and customized its view with a subclass of UIView.
However, I don't know how to call methods of the view in my view controller. Can anyone help? All I want to do is to call drawLine:pointStore in ChartViewController.m from chartView.m
Here are some of my codes.
ChartViewController.h
#import <UIKit/UIKit.h>
#class chartView;
#interface ChartViewController : UIViewController{
chartView *chart_view;
}
ChartViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableDictionary *pointStore = [[NSMutableDictionary alloc]init];
NSNumber *initX;
NSNumber *initY;
NSMutableDictionary *variableSet = [[NSMutableDictionary alloc]init];
for(initX = [NSNumber numberWithDouble:-10.0f];initX.floatValue<=10.0f;initX = [NSNumber numberWithDouble:(initX.floatValue+0.5f)] )
{
[variableSet setValue:initX forKey:#"x"];
initY = [NSNumber numberWithDouble:[self.brain performOperation:equationOfChart withVariable:variableSet]];
[pointStore setObject:initX forKey:initY];
}
[chart_view drawLine:pointStore];
}
chartView.h
#interface chartView : UIView
#property (nonatomic, strong) NSString *equation;
-(void) getEquation:(NSString *)Equation;
-(void) drawLine:(NSMutableDictionary *)pointsStore;
#end
chartView.m
-(void)drawLine:(NSMutableDictionary *)pointsStore{
CGContextRef c = UIGraphicsGetCurrentContext();
CGFloat red[4] = {1.0f, 0.0f, 0.0f, 1.0f};
CGContextSetStrokeColor(c, red);
CGContextBeginPath(c);
CGContextStrokePath(c);
for(NSNumber *ax = [NSNumber numberWithDouble:-10.0f];ax.floatValue<10.0f;){
float ay = [[pointsStore objectForKey:ax]doubleValue];
ax = [NSNumber numberWithDouble:(ax.floatValue+0.5f)];
int by = [[pointsStore objectForKey:ax]doubleValue];
[self.class line:ax.floatValue y:ay x2:(ax.floatValue+0.5) y2:by];
}
}
ChartViewController.h
#import <UIKit/UIKit.h>
#class chartView;
#interface ChartViewController : UIViewController
#property (string, nonatomic) chartView *chart_view;
#end
chartView.m
- (void)viewDidLoad
{
[super viewDidLoad];
...
// Don't forget to alloc and init
self.chart_view = [[chartView alloc] init];
[self.chart_view drawLine:pointStore];
}
You should check that the instance of chart_view is created and assigned. Probably you have nil in that poiner.
How to do this -- depend on the way you have chosen to create the view: in Interface Builder or dynamically, in code.
I want to add more annotations to my mapview. I'm working with a class Annotation where there is a method addAnnotation. This method is being called in my UIViewController when I want to add a new annotation.
But for some reason, only the annotation I added last, is displayed.
Annotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#interface Annotation : NSObject {
CLLocationCoordinate2D cooridnate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, retain) NSMutableArray *locations;
-(void)addAnnotation: (NSString *)initTitle : (NSString *)initSubtitle : (CLLocationCoordinate2D) initCoordinate;
#end
Annotation.m
#import "Annotation.h"
#implementation Annotation
#synthesize coordinate, title, subtitle, locations;
-(void)addAnnotation: (NSString *)initTitle : (NSString *)initSubtitle : (CLLocationCoordinate2D) initCoordinate {
locations = [[NSMutableArray alloc] init];
self.coordinate = initCoordinate;
self.title = [NSString stringWithFormat:#"%#", initTitle];
self.subtitle = [NSString stringWithFormat:#"%#", initSubtitle];
[locations addObject:self]; // add all my anotations with location to an array
}
#end
Method in my UIViewController
#import "MapViewController.h"
#interface MapViewController ()
#end
#implementation MapViewController
#synthesize mapView;
#pragma mark - ViewController methods
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self initMapView];
ann = [[Annotation alloc] init]; // making place in memory
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UIMapController methods
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {
[self createAnnotations];
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
//If annotation = user position ==> DON'T CHANGE
return nil;
}
MKPinAnnotationView *MyPin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"current"];
MyPin.pinColor = MKPinAnnotationColorRed;
UIButton *advertButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[advertButton addTarget:self action:#selector(showInfo:) forControlEvents:UIControlEventTouchUpInside];
MyPin.rightCalloutAccessoryView = advertButton;
MyPin.draggable = NO;
MyPin.highlighted = NO;
MyPin.animatesDrop= FALSE;
MyPin.canShowCallout = YES;
return MyPin;
}
#pragma mark - MY Methods
-(void) initMapView {
[mapView setMapType:MKMapTypeStandard]; // standaard maptype
[mapView setScrollEnabled:YES];
[mapView setZoomEnabled:YES];
[mapView setDelegate:self]; // gegevens van de map terugsturen naar deze viewController en de gebruiker
[mapView setShowsUserLocation:YES];
[self focusWorld];
}
-(void) createAnnotations {
[self initSomeExamples];
[self.mapView addAnnotations: ann.locations];
}
-(void) focusWorld {
MKCoordinateRegion worldRegion = MKCoordinateRegionForMapRect(MKMapRectWorld); // regio instellen op World
mapView.region = worldRegion; // regio doorgeven naar onze mapView
}
-(void) initSomeExamples {
// Washington
l1.latitude = 38.892102;
l1.longitude = -77.029953;
// Antwerp
l2.latitude = 51.219787;
l2.longitude = 4.411011;
// Egypt
l3.latitude = 29.993002;
l3.longitude = 31.157227;
// Brazil
l4.latitude = -22.900846;
l4.longitude = -43.212662;
[ann addAnnotation:#"America has a new President !" :#"Washington DC" :l1]; // call method to add an annotation with these parameters
[ann addAnnotation:#"Revolutionary app by Belgium student" :#"Antwerp" :l2];
[ann addAnnotation:#"The new Arabic revolution" :#"Egypt, Tahir square" :l3];
[ann addAnnotation:#"World Championchip football" :#"Rio de Janeiro" :l4];
}
#pragma mark - ACTIONS
-(void)showInfo:(id)sender {
NSLog(#"Show info");
}
#end
You don't need locations #property and - addAnnotation: method. One MKAnnotation object represents a location.
My suggestion is to modify Annotation class accordingly, as well as conforming and create it's objects as many as number of locations you would like to annotate.
Remove locations #property and -addAnnotation: method from Annotation.h/m
Annotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#interface Annotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
-(id) initWithTitle: (NSString *)initTitle : (NSString *)initSubtitle : (CLLocationCoordinate2D) initCoordinate;
#end
Annotation.m
#import "Annotation.h"
#implementation Annotation
#synthesize coordinate, title, subtitle;
-(id) initWithTitle: (NSString *)initTitle : (NSString *)initSubtitle : (CLLocationCoordinate2D) initCoordinate {
self = [super init];
if ( self ) {
self.coordinate = initCoordinate;
self.title = [NSString stringWithFormat:#"%#", initTitle];
self.subtitle = [NSString stringWithFormat:#"%#", initSubtitle];
}
return self; // correction appreciated.
}
#end
Some methods changed in your view controller
-(void) initSomeExamples {
// Washington
l1.latitude = 38.892102;
l1.longitude = -77.029953;
// Antwerp
l2.latitude = 51.219787;
l2.longitude = 4.411011;
// Egypt
l3.latitude = 29.993002;
l3.longitude = 31.157227;
// Brazil
l4.latitude = -22.900846;
l4.longitude = -43.212662;
NSArray *annotations = #[
[[Annotation alloc] initWithTitle:#"America has a new President !" :#"Washington DC" :l1],
[[Annotation alloc] initWithTitle:#"Revolutionary app by Belgium student" :#"Antwerp" :l2],
[[Annotation alloc] initWithTitle:#"The new Arabic revolution" :#"Egypt, Tahir square" :l3],
[[Annotation alloc] initWithTitle:#"World Championchip football" :#"Rio de Janeiro" :l4] ];
// Adding 4 annotation objects
[self.mapView addAnnotations:annotations];
}
-(void) createAnnotations {
[self initSomeExamples];
// Annotations are added in -initSomeExamples method.
}
I want to change the callout shown on the MKMapView. When I call
[self.mapView selectAnnotation:annotation animated:YES];
it pans the map to the annotation, but does not show its callout. How do I get it to show the callout?
Set the title, and optionally the subtitle property on the annotation object. MapKit will automatically show a callout.
#interface MyAnnotation : NSObject <MKAnnotation> {
NSString *title;
NSString *subtitle;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
And the implementation,
#import "MyAnnotation.h"
#implementation MyAnnotation
#synthesize title, subtitle;
#end
Usage,
MyAnnotation *foo = [[MyAnnotation alloc] init];
foo.title = #"I am Foo";
foo.subtitle = "I am jus' a subtitle";
You should implement the MKAnnotation Delegate method
-(MKAnnotationView *)mapView:(MKMapView *)_mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *AnnotationViewIdentifier = #"AnnotationViewIdentifier";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewIdentifier];
if (annotationView == nil)
{
annotationView = [[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:AnnotationViewIdentifier]autorelease];
}
annotationView.canShowCallout = YES;
return annotationView;
}