Adding pins to MapView - iphone

I was wondering how I would add pins to a MapView within an iPhone app. I want to have pins pinned in places that have the word "Tea" in their name and it would be impractical to place each pin in every place that contains that word, so I was wondering if there's some way to make it so that when the MapView is loaded, the pins are pinned into those places. I assume that this would be done with Google's Map API however I'm unsure as to how I'd exactly do this - does anyone know of any tutorials that would show to implement this.
So far, I have a simple view that contains a MapView as well as a corresponding view controller.
Thanks in advance!

You'll have to add instances of MKAnnotation to your MKMapView.
[mapView addAnnotation:annotation];
annotation is an instance of a class conforming to the MKAnnotation protocol. Read the corresponding documentation here:
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKAnnotation_Protocol/Reference/Reference.html#//apple_ref/occ/intf/MKAnnotation
Sample code:
#interface MyAnnotation: NSObject <MKAnnotation>
{
CLLocationCoordinate2D coordinate;
NSString *title;
}
#end
#implementation MyAnnotation
#synthesize coordinate, title;
- (id) init
{
if ((self = [super init]))
{
coordinate.latitude = 0.0;
coordinate.longitude = 0.0;
title = NSLocalizedString(#"Tea");
}
return self;
}
#end
In your view controller:
- (void) viewDidLoad
{
[super viewDidLoad];
// custom initialiation; create map view
[self addPin]; // or with parameters, called multiple times, to add several annotations
}
- (void) addPin
{
MyAnnotation *ann = [[MyAnnotation alloc] init];
[mapView addAnnotation:ann];
[ann release];
}
Hope this helps.

Related

How to pass annotation title to another view controller

I am new to iOS programming, and I am having trouble with passing data between view controllers.
I have a view controller that geocodes an annotation on a map view, and sets the address as the title of the annotation view. The annotation view has a callout button that pushes another view to the stack, which has a label, and I want the address that was geocoded to show up as the label. Here is some code:
This is where I drop the pin:
-(void)press:(UILongPressGestureRecognizer *)recognizer
{
CGPoint touchPoint = [recognizer locationInView:worldView];
CLLocationCoordinate2D touchMapCoordinate = [worldView convertPoint:touchPoint toCoordinateFromView:worldView];
geocoder = [[CLGeocoder alloc]init];
CLLocation *location = [[CLLocation alloc]initWithCoordinate:touchMapCoordinate
altitude:CLLocationDistanceMax
horizontalAccuracy:kCLLocationAccuracyBest
verticalAccuracy:kCLLocationAccuracyBest
timestamp:[NSDate date]];
[geocoder reverseGeocodeLocation:location
completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"reverseGeocoder:completionHandler: called");
if (error) {
NSLog(#"Geocoder failed with error: %#", error);
}
if (placemarks && placemarks.count > 0)
{
CLPlacemark *place = [placemarks objectAtIndex:0];
_address = [NSString stringWithFormat:#"%# %#, %# %#", [place subThoroughfare], [place thoroughfare], [place locality], [place administrativeArea]];
if (UIGestureRecognizerStateBegan == [recognizer state]) {
_addressPin = [[MapPoint alloc]initWithCoordinate:touchMapCoordinate
title:_address];
[worldView addAnnotation:_addressPin];
}
}
}];
}
Here is the code for the view where I want the address to show up:
#import <UIKit/UIKit.h>
#class MapPoint;
#interface PinViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate,UITextFieldDelegate>
{
__weak IBOutlet UILabel *addressLabel;
}
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#property (strong, nonatomic) MapPoint *pin;
-(void)takePicture:(id)sender;
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
#end
#import "PinViewController.h"
#import "MapPoint.h"
#interface PinViewController ()
#end
#implementation PinViewController
#synthesize imageView, pin;
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[addressLabel setText:[pin title]];
}
The class MapPoint has a title property and subtitle property. When the PinViewController is pushed to the top of the stack, I try to set the text of the label to the title of the pin, but the label does not show any text. Can someone help me out and tell me what I am missing? Your help is greatly appreciated.
You must share more code blocks for this question :) . instead of you have to get more idea about Communication in Object-Oriented Programs
You can read a good tutorial about Passing Data Between View Classes here
Read best way to pass an object between two views here
There is a good document that i found in Developer.apple regarding CommunicatingWithObjects
Also you can watch a good video here
Just create property for the label and pass the label text from callout tapped method
- (void)mapView:(MKMapView *)mapView annotationView:(MKPinAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
Details *det=[[Details alloc]init];
det.label.text=annotation.title;
[self.navigationController pushViewController:det animated:YES];
[det release];
}

MKAnnotation viewForAnnotation never called

I have already add UIViewController<MKMapViewDelegate> in .h and already add
-(void) viewDidLoad {
self.mapView.delegate = self;
}
but the method viewForAnnotation never called
MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface Tela1ViewController : UIViewController<MKMapViewDelegate> {
IBOutlet MKMapView *mapView;
}
#property (nonatomic, retain) MKMapView *mapView;
#end
MapViewController.m
-(void) viewDidLoad {
self.mapView.delegate = self;
}
- (void)viewDidAppear:(BOOL)animated
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication shared
mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
mapView.mapType = MKMapTypeSatellite;
CLLocationCoordinate2D coord = {latitude: appDelegate.latitude, longitude: appDelegate.longitude};
MKCoordinateSpan span = {latitudeDelta:0.2, longitudeDelta: 0.2};
MKCoordinateRegion region = {coord, span};
[mapView setRegion:region];
PlaceMark *addAnnotation = [[PlaceMark alloc] initWithCoordinate:coord];
[mapView addAnnotation:addAnnotation];
[self.view addSubview:mapView];
}
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"test");
}
Okay, couple of things to fix in your code ...
Delegate of MKMapView
Is nil. Why? Because you set delegate of MKMapView in viewDidLoad method. But when you look at viewDidAppear:, you're allocating new MKMapView and you're not setting delegate there. And because viewDidLoad is called before viewDidAppear:, delegate is simply nil = not set.
Calling super
When you override some methods, read documentation. Because you can find this in viewDidAppear: documentation for example:
You can override this method to perform additional tasks associated with presenting the view. If you override this method, you must call super at some point in your implementation.
MKMapView & IBOutlet
And also don't understand why do you have MKMapView as IBOutlet and then you're allocating new MKMapView and adding it as subview. Also if your IBOutlet is really connected to a MKMapView in your XIB, you'll end up with two MKMapViews, because the old one (from XIB) is not removed from superview.
You're clearly messing things up. Go and read more about UIKit, ...
Try replacing the last several lines of you viewDidAppear method with the following:
CLLocationCoordinate2D coord = {.latitude = location.latitude, .longitude = location.longitude};
MKCoordinateSpan span = {.latitudeDelta = 0.2, .longitudeDelta = 0.2};
MKCoordinateRegion region = {coord, span};
[mapView setRegion:region];
MapAnnotation *addAnnotation = [[MapAnnotation alloc] initWithCoordinate:coord];
[mapView addAnnotation:addAnnotation];
[self.view addSubview:mapView];

How to add annotation on center of map view in iPhone?

I have MAP view in my app and i want to add Annotation pin (Red pin) on center of map view.
Now when user scroll map view pin should adjust with center according to that.
How to do that?
Thank
If you want to use an actual annotation instead of just a regular view positioned above the center of the map view, you can:
use an annotation class with a settable coordinate property (pre-defined MKPointAnnotation class eg). This avoids having to remove and add the annotation when the center changes.
create the annotation in viewDidLoad
keep a reference to it in a property, say centerAnnotation
update its coordinate (and title, etc) in the map view's regionDidChangeAnimated delegate method (make sure map view's delegate property is set)
Example:
#interface SomeViewController : UIViewController <MKMapViewDelegate> {
MKPointAnnotation *centerAnnotation;
}
#property (nonatomic, retain) MKPointAnnotation *centerAnnotation;
#end
#implementation SomeViewController
#synthesize centerAnnotation;
- (void)viewDidLoad {
[super viewDidLoad];
MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
pa.coordinate = mapView.centerCoordinate;
pa.title = #"Map Center";
pa.subtitle = [NSString stringWithFormat:#"%f, %f", pa.coordinate.latitude, pa.coordinate.longitude];
[mapView addAnnotation:pa];
self.centerAnnotation = pa;
[pa release];
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:#"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}
- (void)dealloc {
[centerAnnotation release];
[super dealloc];
}
#end
Now this will move the annotation but not smoothly. If you need the annotation to move more smoothly, you can add a UIPanGestureRecognizer and UIPinchGestureRecognizer to the map view and also update the annotation in the gesture handler:
// (Also add UIGestureRecognizerDelegate to the interface.)
// In viewDidLoad:
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
panGesture.delegate = self;
[mapView addGestureRecognizer:panGesture];
[panGesture release];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
pinchGesture.delegate = self;
[mapView addGestureRecognizer:pinchGesture];
[pinchGesture release];
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:#"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
//let the map view's and our gesture recognizers work at the same time...
return YES;
}
Anna's answer is clever approach to keeping an annotation centered in the map using the annotations in the standard mapview way. However, as one commenter pointed out, the scrolling and pinching while much better still shows noticeable lag, and the recommended approach would be to add the annotation view as a subview of the mapview. Here's what that looks like.
#interface SHCenterPinMapViewController () <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (strong, nonatomic) MKPointAnnotation *centerAnnotaion;
#property (strong, nonatomic) MKPinAnnotationView *centerAnnotationView;
#end
#implementation SHCenterPinMapViewController
- (MKPointAnnotation *)centerAnnotaion
{
if (!_centerAnnotaion) {
_centerAnnotaion = [[MKPointAnnotation alloc] init];
}
return _centerAnnotaion;
}
- (MKPinAnnotationView *)centerAnnotationView
{
if (!_centerAnnotationView) {
_centerAnnotationView = [[MKPinAnnotationView alloc] initWithAnnotation:self.centerAnnotaion
reuseIdentifier:#"centerAnnotationView"];
}
return _centerAnnotationView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
[self.mapView addSubview:self.centerAnnotationView];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self moveMapAnnotationToCoordinate:self.mapView.centerCoordinate];
}
// These are the constants need to offset distance between the lower left corner of
// the annotaion view and the head of the pin
#define PIN_WIDTH_OFFSET 7.75
#define PIN_HEIGHT_OFFSET 5
- (void)moveMapAnnotationToCoordinate:(CLLocationCoordinate2D) coordinate
{
CGPoint mapViewPoint = [self.mapView convertCoordinate:coordinate toPointToView:self.mapView];
// Offset the view from to account for distance from the lower left corner to the pin head
CGFloat xoffset = CGRectGetMidX(self.centerAnnotationView.bounds) - PIN_WIDTH_OFFSET;
CGFloat yoffset = -CGRectGetMidY(self.centerAnnotationView.bounds) + PIN_HEIGHT_OFFSET;
self.centerAnnotationView.center = CGPointMake(mapViewPoint.x + xoffset,
mapViewPoint.y + yoffset);
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
self.centerAnnotaion.coordinate = mapView.centerCoordinate;
[self moveMapAnnotationToCoordinate:mapView.centerCoordinate];
}
#end
Really the only interesting thing to not is that you have to offset the MKPinAnnotationView by a certain amount to account for the distance between the lower left corner and the pin head. I don't like having these asset dependent constants in the code, so if anyone can find a better way to do that, I am all ears.
I created a github project with a map controller that does this as well as some other things related to using a mapview to have a user select a location. Check it out here: https://github.com/scottrhoyt/CenterPinMapViewController
Swift version
In class:
var centerAnnotation = MKPointAnnotation()
var centerAnnotationView = MKPinAnnotationView()
In viewDidLoad:
if #available(iOS 9.0, *) {
centerAnnotationView.pinTintColor = customColor
} else {
// Fallback on earlier versions
centerAnnotationView.pinColor = MKPinAnnotationColor.Red
}
self.view.addSubview(centerAnnotationView)
In viewDidAppear:
self.moveMapAnnotationToCoordinate(self.mapView.centerCoordinate)
Then:
func moveMapAnnotationToCoordinate(locate : CLLocationCoordinate2D ) {
let mapViewPoint : CGPoint = self.mapView.convertCoordinate(locate, toPointToView: self.mapView)
let pinWidth : CGFloat = 7.75
let pinHeight : CGFloat = 7
let xOffset : CGFloat = CGRectGetMidX(self.centerAnnotationView.bounds) - pinWidth
let yOffset : CGFloat = CGRectGetMidY(self.centerAnnotationView.bounds) - pinHeight
self.centerAnnotationView.center = CGPointMake(mapViewPoint.x - xOffset, mapViewPoint.y - yOffset)
}
For using change in location, add delegate CLLocationManagerDelegate and then:
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
self.centerAnnotation.coordinate = self.mapView.centerCoordinate
self.moveMapAnnotationToCoordinate(self.mapView.centerCoordinate)
}

Display annotation in Map kit

I am working with Mapkit and I have to show annotations in the map but I'm not able to display the annotation. Here's my code:
#interface MyMapView : UIViewController <MKAnnotation,MKMapViewDelegate>{
MKMapView *Obj_Map_View;
MKPlacemark *pmark;
MKReverseGeocoder *geocoder1;
}
#end
#import "MyMapView.h"
#implementation MyMapView
- (id)init {
if (self = [super init]) {
}
return self;
}
- (void)loadView {
[super loadView];
Obj_Map_View = [[MKMapView alloc]initWithFrame:self.view.bounds];
Obj_Map_View.showsUserLocation =YES;
Obj_Map_View.mapType=MKMapTypeStandard;
[self.view addSubview:Obj_Map_View];
Obj_Map_View.delegate = self;
CLLocationCoordinate2D cord = {latitude: 19.120000, longitude: 73.020000};
MKCoordinateSpan span = {latitudeDelta:0.3, longitudeDelta:0.3};
MKCoordinateRegion reg= {cord,span};
[Obj_Map_View setRegion:reg animated:YES];
//[Obj_Map_View release];
}
- (NSString *)subtitle{
return #"Sub Title";
}
- (NSString *)title{
return #"Title";
}
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
MKPinAnnotationView *annov = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"Current location"];
annov.animatesDrop = TRUE;
[annotation title]==#"Current location";
annov.canShowCallout = YES;
[annov setPinColor:MKPinAnnotationColorGreen];
return annov;
}
The above code works fine and displays a map but not with annotation.
Typically, the class that conforms to the MKAnnotation protocol isn't the view controller, it's a data class.
You'll need to create another class, which I'll call "MyLandmarks" for the example.
#interface MyLandmarks : NSObject <MKAnnotation>
// Normally, there'd be some variables that contain the name and location.
// And maybe some means to populate them from a URL or a database.
// This example hard codes everything.
#end
#implementation MyLandmarks
-(NSString*)title {
return #"'ere I am, J.H.";
}
-(NSString*)subtitle {
return #"The ghost in the machine.";
}
-(CLLocationCoordinate2D) coordinate {
CLLocationCoordinate2D coord = {latitude: 19.120000, longitude: 73.020000};
return coord;
}
#end
Then, somewhere appropriate in your MyMapView class add:
MyLandmark *landmark = [[[MyLandmark alloc]init]autorelease];
[Obj_Map_View addAnnotation:landmark];
A couple other bits that other Objective-C developers working with you will appreciate:
To avoid confusion, don't call the class MyMapView if it descends from a UIViewController. Call it MyMapViewController, instead.
Classes start with a capital letter, variables start lowercase. Both are CamelCased. Obj_Map_View should be objMapView.
To add annotation use : addAnnotation:
read about it here

initializing the mapkit with a particular latitude and longitude Iphone

Iam making an iphone app, which should take in latitude and longitudes from an array and should locate and display the map with a customized annotation/pins. I have used the mapkit here's how:
//MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController <MKMapViewDelegate> {
IBOutlet MKMapView *mapView;
MKPlacemark *mPlacemark;
}
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#end
//MapViewController.m
#import "MapViewController.h"
#import <MapKit/MapKit.h>
#implementation MapViewController
#synthesize mapView;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
CLLocationCoordinate2D location = mapView.userLocation.coordinate;
MKCoordinateRegion region;
MKCoordinateSpan span;
location.latitude = 37.250556;
location.longitude = -96.358333;
span.latitudeDelta = 0.05;
span.longitudeDelta = 0.05;
region.span = span;
region.center = location;
[mapView setRegion:region animated:YES];
[mapView regionThatFits:region];
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[mapView setNeedsDisplay];
}
#end
This does not locate the place for the latitude and longitude. Please help.
I have made a sample project with your code and it works fine - map gets positioned to the expected (it seems) region. Check if your mapView ivar is initialized (are connections set properly in IB?)
Edit: In your code you just set map's visible region but do not add any annotations to it (apart from automatically showing current user position which is always in Cupertino if you test on simulator). To put pin to you map you need to create an object confirming to MKAnnotation protocol and add it to mapView:
// Sample example just to show annotation
// in your program you will likely need to use custom annotation objects
CLLocation* myLocation = [[CLLocation alloc] initWithLatitude:37.250556 longitude:-96.358333];
[mapView addAnnotation:myLocation];
Some (not so relevant) comments on your code:
You don't need to initialize location variable with current location as you overwrite its coordinate values immediately after that
Why do you call [mapView setNeedsDisplay]; in viewDidUnload method? I'm not sure if this may cause serious problems but you must use this method for cleaning memory up (e.g. releasing retained outlets), not for redrawing your UI
Have you set your map to follow user location somewhere else? maybe that default is overruling your manual movement of the map to Kansas.
edit
Do'h, didn't see this was July last year. Well maybe you could share your solution with us if this wasn't the problem