I am using below piece of code using to interact with MBTiles. But singleTapOnMap method is not calling when i run it on iphone. I also added Trailer which is working on TileMill, but not on iPhone. Whether i have gone wrong anywhere?
//ViewController.h
#interface ViewController : UIViewController<RMMapViewDelegate>
#end
//ViewController.m
- (void)viewDidLoad
{
RMMBTilesSource *offlineSource = [[RMMBTilesSource alloc] initWithTileSetResource:#"MYMAP" ofType:#"mbtiles"];
RMMapView *mapView = [[RMMapView alloc] initWithFrame:self.view.bounds andTilesource:offlineSource];
mapView.zoom = 2;
mapView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
mapView.adjustTilesForRetinaDisplay = YES; // these tiles aren't designed specifically for retina, so make them legible
[self.view addSubview:mapView];
}
#pragma mark -
- (void)singleTapOnMap:(RMMapView *)mapView at:(CGPoint)point
{
[mapView removeAllAnnotations];
RMMapBoxSource *source = (RMMapBoxSource *)mapView.tileSource;
NSLog(#"You tapped at %f, %f", [mapView pixelToCoordinate:point].latitude, [mapView pixelToCoordinate:point].longitude);
if ([source conformsToProtocol:#protocol(RMInteractiveSource)] && [source supportsInteractivity])
{
NSString *formattedOutput = [source formattedOutputOfType:RMInteractiveSourceOutputTypeTeaser
forPoint:point
inMapView:mapView];
if (formattedOutput && [formattedOutput length])
{
// parse the country name out of the content
//
NSUInteger startOfCountryName = [formattedOutput rangeOfString:#"<strong>"].location + [#"<strong>" length];
NSUInteger endOfCountryName = [formattedOutput rangeOfString:#"</strong>"].location;
NSString *countryName = [formattedOutput substringWithRange:NSMakeRange(startOfCountryName, endOfCountryName - startOfCountryName)];
// parse the flag image out of the content
//
NSUInteger startOfFlagImage = [formattedOutput rangeOfString:#"base64,"].location + [#"base64," length];
NSUInteger endOfFlagImage = [formattedOutput rangeOfString:#"\" style"].location;
UIImage *flagImage = [UIImage imageWithData:[NSData dataFromBase64String:[formattedOutput substringWithRange:NSMakeRange(startOfFlagImage, endOfFlagImage)]]];
RMAnnotation *annotation = [RMAnnotation annotationWithMapView:mapView coordinate:[mapView pixelToCoordinate:point] andTitle:countryName];
annotation.userInfo = flagImage;
[mapView addAnnotation:annotation];
[mapView selectAnnotation:annotation animated:YES];
}
}
}
- (RMMapLayer *)mapView:(RMMapView *)mapView layerForAnnotation:(RMAnnotation *)annotation
{
RMMarker *marker = [[RMMarker alloc] initWithMapBoxMarkerImage:#"embassy"];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 32)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image = annotation.userInfo;
marker.leftCalloutAccessoryView = imageView;
marker.canShowCallout = YES;
return marker;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
You have to assign the delegate protocol:
mapView.delegate = self;
Related
Is there any way to change default marker icon in marker clustering?
Here is my code...
- (void)viewDidLoad {
[super viewDidLoad];
// Set up the cluster manager with a supplied icon generator and renderer.
id<GMUClusterAlgorithm> algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init];
id<GMUClusterIconGenerator> iconGenerator = [[GMUDefaultClusterIconGenerator alloc] init];
id<GMUClusterRenderer> renderer = [[GMUDefaultClusterRenderer alloc] initWithMapView:googleMapView
clusterIconGenerator:iconGenerator];
clusterManager = [[GMUClusterManager alloc] initWithMap:googleMapView
algorithm:algorithm
renderer:renderer];
// Register self to listen to both GMUClusterManagerDelegate and
// GMSMapViewDelegate events.
[clusterManager setDelegate:self mapDelegate:self];
}
- (void)loadView {
// Create a GMSCameraPosition that tells the map to display the
_camera = [GMSCameraPosition cameraWithLatitude:29.3117
longitude:47.4818
zoom:8];
googleMapView = [GMSMapView mapWithFrame:CGRectZero camera:_camera];
googleMapView.myLocationEnabled = YES;
googleMapView.settings.compassButton = YES;
googleMapView.settings.myLocationButton = YES;
googleMapView.delegate = self;
self.view = googleMapView;
}
-(void)setLocation:(CLLocation *)location
{
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
[googleMapView animateToLocation:center];
[googleMapView animateToZoom:12];
NSMutableArray *array = [NSMutableArray arrayWithObjects:
#"29.0827,48.1363",
#"29.2679,47.9927",
#"29.348706, 48.092425",
#"29.340925, 48.088477",
#"29.324912, 48.089850",
#"29.330599, 47.990630",
#"29.300364, 47.960589",
#"29.271917, 47.918017",
#"29.3032,47.936", nil];
//remove all clusters before adding clusters
[clusterManager clearItems];
for (int i = 0; i < [array count]; i++)
{
center = CLLocationCoordinate2DMake ([[array[i] componentsSeparatedByString:#","][0] floatValue], [[array[i] componentsSeparatedByString:#","][1] floatValue]);
// Add items to the cluster manager.
NSString *name = nil;//[NSString stringWithFormat:#"Item %d", i];
id<GMUClusterItem> item =[[POIItem alloc] initWithPosition:center
name:name];
[clusterManager addItem:item];
}
// Call cluster() after items have been added
// to perform the clustering and rendering on map.
[clusterManager cluster];
}
Please guide me...
I see that you used google-maps-ios-utils. The problem is that there is no API for change marker's icon yet. You can only do it directly in the code of the library. I've pasted my custom code inside the method
- (GMSMarker *)markerWithPosition:(CLLocationCoordinate2D)position
from:(CLLocationCoordinate2D)from
userData:(id)userData
clusterIcon:(UIImage *)clusterIcon
animated:(BOOL)animated{
//...
if (clusterIcon != nil) {
marker.icon = clusterIcon;
marker.groundAnchor = CGPointMake(0.5, 0.5);
} else {
if([[marker.userData class] isSubclassOfClass:[POIItem class]]){
POIItem *item = (POIItem *)marker.userData;
MarkerIcon* markerView = (MarkerIcon *)[[NSBundle mainBundle] loadNibNamed:#"MarkerIcon" owner:marker options:nil][0];
marker.iconView = markerView;
marker.groundAnchor = CGPointMake(0.5, 0.5);
}
}
}
It is not a good way to change the code like this. But I could not find better solution for that moment.
I have already sovled this question.
I used googleMaps Api version:8.1.
Here is my code...
#import "Clustering/GMUClusterItem.h"
// Point of Interest Item which implements the GMUClusterItem protocol.
#interface POIItem : NSObject<GMUClusterItem>
#property(nonatomic, readonly) CLLocationCoordinate2D position;
#property(nonatomic, readonly) NSString *name;
- (instancetype)initWithPosition:(CLLocationCoordinate2D)position name:(NSString *)name;
#end
1.creat the map.
#interface BasicViewController ()<GMUClusterManagerDelegate, GMSMapViewDelegate,
GMUClusterRendererDelegate>
#end
typedef NS_ENUM(NSInteger, ClusterAlgorithmMode) {
kClusterAlgorithmGridBased,
kClusterAlgorithmQuadTreeBased,
};
#implementation BasicViewController {
GMSMapView *_mapView;
GMUClusterManager *_clusterManager;
}
- (void)loadView {
//创建地图
GMSCameraPosition *camera =
[GMSCameraPosition cameraWithLatitude:kCameraLatitude longitude:kCameraLongitude zoom:10];
_mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.view = _mapView;
}
2.creat GMUClusterManager object.
- (void)viewDidLoad {
[super viewDidLoad];
//添加标注算法方式
id<GMUClusterAlgorithm> algorithm = [self algorithmForMode:kClusterAlgorithmQuadTreeBased];
//标注icon
id<GMUClusterIconGenerator> iconGenerator = [self iconGeneratorWithImages];//[self defaultIconGenerator];
// CustomClusterIconGenerator *iconGenerator = [[CustomClusterIconGenerator alloc] init];
GMUDefaultClusterRenderer *renderer =
[[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView
clusterIconGenerator:iconGenerator];
renderer.delegate = self;
_clusterManager =
[[GMUClusterManager alloc] initWithMap:_mapView algorithm:algorithm renderer:renderer];
// Generate and add random items to the cluster manager.
//将标注添加到地图上
[self generateClusterItems];
// Call cluster() after items have been added to perform the clustering and rendering on map.
//展示
[_clusterManager cluster];
// Register self to listen to both GMUClusterManagerDelegate and GMSMapViewDelegate events.
[_clusterManager setDelegate:self mapDelegate:self];
UIBarButtonItem *removeButton =
[[UIBarButtonItem alloc] initWithTitle:#"Remove"
style:UIBarButtonItemStylePlain
target:self
action:#selector(removeClusterManager)];
self.navigationItem.rightBarButtonItems = #[ removeButton ];
}
3.in method :
/*You can set marker image here
if [marker class] is POIItem.
*/
- (void)renderer:(id<GMUClusterRenderer>)renderer willRenderMarker:(GMSMarker *)marker {
if ([marker.userData isKindOfClass:[POIItem class]]) {
POIItem *item = marker.userData;
marker.title = item.name;
******marker.icon = [UIImage imageNamed:#"register"];******
}
}
Hello friends i am uploading my code from last few days on the stackoverflow but somwhow i am not getting the thing which i want. Noe once again i am trying this please try to help me out and solve my proplems. Firstly see the code.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
welcomeViewController.h
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#import <UIKit/UIKit.h>
#import <GoogleMaps/GoogleMaps.h>
#interface welcomemapViewController : UIViewController
#property (strong, nonatomic) UITextField *txt;
#end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
welcomeViewController.m
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#import "welcomemapViewController.h"
#import <GoogleMaps/GoogleMaps.h>
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define kLatestSearchURL [NSURL URLWithString: #"https://maps.googleapis.com/maps/api/place/textsearch/xml?query=Delhi&sensor=true&key=Your API key"]
#interface welcomemapViewController ()
#end
#implementation welcomemapViewController
{
GMSMapView *gmap;
}
#synthesize txt;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
GMSCameraPosition *cam = [GMSCameraPosition cameraWithLatitude:30.7343000 longitude:76.7933000 zoom:12];
gmap = [GMSMapView mapWithFrame:CGRectMake(0, 60, 320, 480) camera:cam];
gmap.myLocationEnabled = YES;
gmap.mapType = kGMSTypeHybrid;
gmap.settings.myLocationButton = YES;
gmap.settings.zoomGestures = YES;
gmap.settings.tiltGestures = NO;
gmap.settings.rotateGestures = YES;
[self.view addSubview:gmap];
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(30.751288, 76.780899);
marker.title = #"Sector -16";
marker.snippet = #"Chandigarh";
marker.map = gmap;
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(200, 65, 100, 40);
[button setTitle:#"SEARCH" forState:UIControlStateNormal];
[button addTarget:self action:#selector(search:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
CGRect frame2 = CGRectMake(10, 68, 200, 30);
txt =[[UITextField alloc]initWithFrame:frame2];
txt.placeholder = #"Search";
txt.userInteractionEnabled = YES;
txt.keyboardType = UIKeyboardTypeAlphabet;
[txt setBorderStyle:UITextBorderStyleRoundedRect];
[self.view addSubview:txt];
// Do any additional setup after loading the view from its nib.
}
-(IBAction)search:(id)sender
{
NSString *url = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=30.7343000,76.7933000&radius=500&types=food&name&sensor=true&key=AIzaSyCGeIN7gCxU8baq3e5eL0DU3_JHeWyKzic"];
//Formulate the string as URL object.
NSURL *googleRequestURL=[NSURL URLWithString:url];
// Retrieve the results of the URL.
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: googleRequestURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
}
- (void)fetchedData:(NSData *)responseData {
//parse out the json data
NSString *data1 = [NSString stringWithUTF8String:[responseData bytes]];
NSLog(#"Response data: %#", data1);
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
//The results from Google will be an array obtained from the NSDictionary object with the key "results".
NSArray* responseResults = [json objectForKey:#"results"];
NSLog(#"Locations are %#", responseResults);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
now in "NSLog(#"Locations are %#", responseResults);" i am getting my values, i simply want to add these values onto the map in the form of pointers with details.
So kindly help me how it should be done. (And kindly help me with the help of codes)
you can do this by using MKPointAnnotation and then add this MKPointAnnotation in you mapview
CLLocationCoordinate2D annotationCoord;
annotationCoord.latitude = #"your Latitude to point on map";
annotationCoord.longitude = #"your Longitude to point on map";;
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
annotationPoint.title = #"your title";
annotationPoint.subtitle = #"your subtitle";
[YourmapView addAnnotation:annotationPoint];
My app is a map view where the user can enter an address which will put a purple pin on the map for the HQ. Secondly, the user can enter any address, which will put a red pin on the map. I would like to be able to change the pin color of the red pins to either red, green, or purple.
I stumbled across a tutorial that will allow the user to select an annotation pin and change its pin color by displaying a modal view. I followed the tutorial meticulously, but for some reason, it is not working correctly. The modal view with the pin selection is displayed, but when a pin color is selected, the pin color on the map view is not updated. Additionally, instead of using "png" images to display custom pins, I would like to use the built-in standard pins (since that's all I need). How can I adjust my code below to achieve this? I added my entire code.
FieldMapController.m
#import "FieldMapController.h"
#import "CustomAnnotation.h"
#define HQ_latitude #"headquarters_latitude"
#define HQ_longitude #"headquarters_longitude"
#define HQ_coordinates #"headquarters_coordinates"
#import "PinSelectionViewController.h"
#interface FieldMapController ()
#end
#implementation FieldMapController
#synthesize mapView;
#synthesize searchBar;
#synthesize geocoder = _geocoder;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
//ACCESS SAVED DATA FROM NSUSERDEFAULTS
-(void)viewWillAppear:(BOOL)animated{
NSUserDefaults *uDefaults = [NSUserDefaults standardUserDefaults];
if ([uDefaults boolForKey:#"headquarters_coordinates"])
{
CLLocationCoordinate2D savedCoordinate;
savedCoordinate.latitude = [uDefaults doubleForKey:#"headquarters_latitude"];
savedCoordinate.longitude = [uDefaults doubleForKey:#"headquarters_longitude"];
NSLog(#"Your HQ is at coordinates %f and %f",savedCoordinate.latitude, savedCoordinate.longitude);
CustomAnnotation *annHq =[[CustomAnnotation alloc] init];
annHq.title=#"HQ";
annHq.subtitle=#"";
annHq.coordinate= savedCoordinate;
[mapView addAnnotation:annHq];
MKCoordinateRegion viewRegion = {{0.0, 0.0}, {0.0, 0.0}};
viewRegion.center.latitude = savedCoordinate.latitude;
viewRegion.center.longitude = savedCoordinate.longitude;
viewRegion.span.longitudeDelta = 0.5f;
viewRegion.span.latitudeDelta = 0.5f;
[self.mapView setRegion:viewRegion animated:YES];
[self.mapView setDelegate:self];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.mapView.delegate = self;
self.searchBar.delegate = self;
//SEARCH BAR TOOLBAR WITH "DONE" AND "CANCEL" BUTTON
UIToolbar* searchToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
searchToolbar.barStyle = UIBarStyleBlackTranslucent;
searchToolbar.items = [NSArray arrayWithObjects:
[[UIBarButtonItem alloc]initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:self action:#selector(cancelSearchBar)],
[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
nil];
[searchToolbar sizeToFit];
searchBar.inputAccessoryView = searchToolbar;
}
//WHEN PUSHING THE "CANCEL" BUTTON IN THE SEARCH BAR
-(void)cancelSearchBar
{
[searchBar resignFirstResponder];
searchBar.text = #"";
}
//PREPARE SEGUE FOR THE PIN SELECTOR VIEW
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"ShowPinChoicesSegue"])
{
PinSelectionViewController *pinVC = [segue destinationViewController];
CustomAnnotation *selectedAnnotation = (CustomAnnotation *)sender;
pinVC.currentPinType = selectedAnnotation.pinType;
pinVC.delegate = self;
}
}
//WHAT HAPPENS WHEN THE "SEARCH" BUTTON AT THE SEARCH BAR KEYBOARD IS TAPPED
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
//Forward Geocoder
if (!self.geocoder)
{
self.geocoder = [[CLGeocoder alloc] init];
}
NSString *address = [NSString stringWithFormat:#"%#", self.searchBar.text];
[self.geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > 0)
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
//Display Coordinates in Console
NSLog (#"%f %f", coordinate.latitude, coordinate.longitude);
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.01;
span.longitudeDelta = 0.01;
region.span = span;
region.center = coordinate;
//Create Annotation with Callout Bubble that displays "No Information"
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:coordinate];
[annotation setTitle:#"No Information"];
[[self mapView] addAnnotation:annotation];
[self.mapView setRegion:region animated:TRUE];
[self.mapView regionThatFits:region];
//Dismiss the Search Bar Keyboard
[self.searchBar resignFirstResponder];
//Delete text in Search Bar
self.searchBar.text = #"";
}
}];
}
//CUSTOM ANNOTATION VIEW
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
return nil;
}
if ([annotation isKindOfClass:[CustomAnnotation class]])
{
MKPinAnnotationView *annotationView =
(MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:((CustomAnnotation *)annotation).annotationViewImageName];
if(annotationView == nil)
{
MKPinAnnotationView *customPinView =
[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:((CustomAnnotation *)annotation).annotationViewImageName];
if([[customPinView.annotation title] isEqualToString:#"HQ"])
{
//The pin for the HQ should be purple
customPinView.pinColor = MKPinAnnotationColorPurple;
}
else
{
//All other new pins should be "red" by default
customPinView.image = [UIImage imageNamed:((CustomAnnotation *)annotation).annotationViewImageName];
}
customPinView.canShowCallout = YES;
customPinView.animatesDrop = YES;
//Right Callout Accessory Button
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}
else
{
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
//SHOW ACCESSORY VIEW WHEN BUTTON ON CALLOUT BUBBLE IS TAPPED
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
if (![view.annotation isKindOfClass:[CustomAnnotation class]])
return;
CustomAnnotation *customAnnotation = (CustomAnnotation *)view.annotation;
if (control.tag == 0)
{
[self performSegueWithIdentifier:#"ShowPinChoicesSegue" sender:customAnnotation];
}
else
{
[self onRightCalloutAccessoryViewTouched:control];
}
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
if(![view.annotation isKindOfClass:[CustomAnnotation class]])
return;
if (!view.rightCalloutAccessoryView)
{
UIButton *rightViewButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 48.0, 32.0)];
[rightViewButton addTarget:self action:#selector(onRightCalloutAccessoryViewtouched:) forControlEvents:UIControlEventTouchUpInside];
rightViewButton.tag = 1;
view.rightCalloutAccessoryView = rightViewButton;
}
}
-(void)onRightCalloutAccessoryViewTouched:(id)sender
{
CustomAnnotation *selectedAnnotation = (CustomAnnotation *)[mapView.selectedAnnotations objectAtIndex:0];
[self performSegueWithIdentifier:#"ShowPinChoicesSegue" sender:selectedAnnotation];
}
- (void)viewDidUnload
{
self.mapView = nil;
self.searchBar = nil;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
//BUTTON TO SELECT NEW HQ
- (IBAction)selectHq:(UIBarButtonItem *)sender
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Select Headquarters"
message:#"Enter Address"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Ok", nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[[alert textFieldAtIndex:0] setKeyboardType:UIKeyboardTypeDefault];
[alert show];
}
//REMOVING ALL PINS EXCEPT USER LOCATION
- (IBAction)resetPins:(UIBarButtonItem *)sender
{
id userLocation = [mapView userLocation];
NSMutableArray *pins = [[NSMutableArray alloc] initWithArray:[mapView annotations]];
if ( userLocation != nil )
{
[pins removeObject:userLocation]; //avoid removing user location
}
[mapView removeAnnotations:pins];
pins = nil;
[[NSUserDefaults standardUserDefaults] removeObjectForKey:HQ_coordinates];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:HQ_longitude];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:HQ_latitude];
}
//ALERT VIEW TO ENTER ADDRESS OF HQ
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != alertView.cancelButtonIndex)
{
UITextField *field = [alertView textFieldAtIndex:0];
field.placeholder = #"Enter HQ Address";
if (!self.geocoder)
{
self.geocoder = [[CLGeocoder alloc] init];
}
NSString *hqAddress = [NSString stringWithFormat:#"%#", field.text];
[self.geocoder geocodeAddressString:hqAddress completionHandler:^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > 0)
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D hqCoordinate = location.coordinate;
NSLog (#"Your new HQ is at coordinates %f and %f", hqCoordinate.latitude, hqCoordinate.longitude);
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.01;
span.longitudeDelta = 0.01;
region.span = span;
region.center = hqCoordinate;
MKPointAnnotation *hqAnnotation = [[MKPointAnnotation alloc] init];
[hqAnnotation setCoordinate:hqCoordinate];
[hqAnnotation setTitle:#"HQ"];
[[self mapView] addAnnotation:hqAnnotation];
[self.mapView setRegion:region animated:TRUE];
[self.mapView regionThatFits:region];
//Save to NSUserDefaults
NSUserDefaults *uDefaults = [NSUserDefaults standardUserDefaults];
[uDefaults setDouble:hqCoordinate.latitude forKey:HQ_latitude];
[uDefaults setDouble:hqCoordinate.longitude forKey:HQ_longitude];
[uDefaults setBool:YES forKey:HQ_coordinates];
[uDefaults synchronize];
}
}];
}
else
{
//any actions for "Cancel"
}
}
//DEFINES WHAT SELECTING THE NEW PIN COLOR DOES
-(void)userDidSelectPinType:(AnnotationPinType)aPinType
{
CustomAnnotation *selectedAnnotation = (CustomAnnotation *)[mapView.selectedAnnotations objectAtIndex:0];
selectedAnnotation.pinType = aPinType;
[mapView removeAnnotation:selectedAnnotation];
[mapView addAnnotation:selectedAnnotation];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
#end
CustomAnnotation.m
#import "CustomAnnotation.h"
#import <CoreLocation/CoreLocation.h>
#implementation CustomAnnotation
#synthesize title, subtitle, coordinate;
#synthesize pinType;
-(id) initWithCoordinate:(CLLocationCoordinate2D)aCoordinate title:(NSString *)aTitle subtitle:(NSString *)aSubtitle
{
if ((self = [super init]))
{
self.title = aTitle;
self.coordinate = aCoordinate;
self.subtitle = aSubtitle;
}
return self;
}
- (NSString *)annotationViewImageName
{
switch (self.pinType)
{
case 0:
return #"Red_Pin.png";
break;
case 1:
return #"Green_Pin.png";
break;
case 2:
return #"Purple_Pin.png";
break;
default:
break;
}
}
- (NSString *)title
{
return title;
}
- (NSString *)subtitle
{
return subtitle;
}
#end
PinSelectionViewController.m
#import "PinSelectionViewController.h"
#interface PinSelectionViewController ()
#end
#implementation PinSelectionViewController
#synthesize delegate;
#synthesize currentPinType;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (void)tableView:(UITableView *) tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row ==currentPinType)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate userDidSelectPinType:indexPath.row];
}
#end
PinSelectionDelegateProtocol.h
#import <Foundation/Foundation.h>
typedef enum
{
RED_PIN,
GREEN_PIN,
PURPLE_PIN
} AnnotationPinType;
#protocol PinSelectionDelegate <NSObject>
#required
-(void)userDidSelectPinType:(AnnotationPinType)aPinType;
#end
The problem I see is early on in your viewForAnnotation method. You correctly reuse annotationviews but incorrectly assume that the reused view is configured properly. When you check if the view is nil you only configure brand new ones to have the pin colour that matches the annotation's name. What you need to do is check if it is nil, if is then make a new one and close that if. Then make sure both new and reused annotationviews have their pin colour, title, accessory view etc set up as you want it for that annotation.
Also you can't set the .image of an MKPinAnnotationView, it'll just get overwritten. If you really want to set a custom image you have to use a regular MKAnnotationView. If you are ok with using the standard red, green and blue pins then just set the .pinColor to whatever you want.
Hi I'm doing an app that must to show a map with the route. I parsed a Json to obtain the points to draw the polyline. I found a a code in the web to draw this polyline. The code I found it's on this link: http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/
Where it says "Create the MKPolyline annotation" I tried to import this in my app, but I'm having problems to create the array of the coordinates. My method is this:
- (void)createMKpolylineAnnotation {
NSInteger numberOfSteps = self.path.count;
CLLocationCoordinate2D *coords = malloc(sizeof(CLLocationCoordinate2D) * numberOfSteps);
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [self.path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coords[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coords count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
When I try to look the value of coords is setted only the first time, why's that?
Can you help me to solve this problem or i should make in another mode?
I post here the code of the view controller that handle the map view.
MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (nonatomic, strong) NSString *fromCity;
#property (nonatomic, strong) NSString *toCity;
- (IBAction)chooseKindOfMap:(id)sender;
#end
MapViewController.m
#import "MapViewController.h"
#import "AppDelegate.h"
#import "PlaceAnnotation.h"
#interface MapViewController ()
#property (nonatomic, strong)NSMutableArray *mapAnnotation;
#property (nonatomic) BOOL needUpdateRegion;
#property (nonatomic, strong)NSMutableArray *path;
#end
#implementation MapViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self parseGoogleJsonToObtainPointsForPolyline];
[self.mapView setDelegate:self];
self.needUpdateRegion = YES;
//[self centerMap];
self.mapAnnotation = [[NSMutableArray alloc]initWithCapacity:2];
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
NSLog(#"%d", appDelegate.dataForMap.count);
NSArray* coords = [self getCoords:appDelegate.dataForMap];
NSLog(#"coords = %#", coords);
PlaceAnnotation *fromPlace = [[PlaceAnnotation alloc] initWithCoordinateAndName:coords[0] andLong:coords[1] andName:self.fromCity];
PlaceAnnotation *toPlace = [[PlaceAnnotation alloc] initWithCoordinateAndName:coords[2] andLong:coords[3] andName:self.toCity];
[self.mapAnnotation insertObject:fromPlace atIndex:0];
[self.mapAnnotation insertObject:toPlace atIndex:1];
NSLog(#"mapAnnotation.count: %d", self.mapAnnotation.count);
if (self.mapAnnotation) {
[self.mapView removeAnnotations:self.mapView.annotations];
}
[self.mapView addAnnotation:self.mapAnnotation[0]];
[self.mapView addAnnotation:self.mapAnnotation[1]];
NSLog(#"MapAnnotation = %#", self.mapView.annotations);
[self updateRegion];
[self createMKpolylineAnnotation];
}
//- (void)viewDidAppear:(BOOL)animated {
// [super viewDidAppear:animated];
// if (self.needUpdateRegion) [self updateRegion];
//}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
MKPinAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
pin.pinColor = MKPinAnnotationColorRed;
return pin;
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
MKPinAnnotationView *ulv = [mapView viewForAnnotation:mapView.userLocation];
ulv.hidden = YES;
}
- (NSArray*)getCoords:(NSDictionary*)data {
NSArray *legs = [data objectForKey:#"legs"];
NSDictionary *firstZero = [legs objectAtIndex:0];
NSDictionary *endLocation = [firstZero objectForKey:#"end_location"];
NSDictionary *startLocation = [firstZero objectForKey:#"start_location"];
NSString *latFrom = [startLocation objectForKey:#"lat"];
NSString *lngFrom = [startLocation objectForKey:#"lng"];
NSString *latTo = [endLocation objectForKey:#"lat"];
NSString *lngTo = [endLocation objectForKey:#"lng"];
return #[latFrom,lngFrom,latTo,lngTo];
}
- (void)centerMap {
MKCoordinateRegion region;
region.center.latitude = 41.178654;
region.center.longitude = 11.843262;
region.span.latitudeDelta = 11.070406;
region.span.longitudeDelta = 12.744629;
[self.mapView setRegion:region];
}
- (IBAction)chooseKindOfMap:(id)sender {
if ([sender tag] == 0) {
self.mapView.mapType = MKMapTypeStandard;
}
if ([sender tag] == 1) {
self.mapView.mapType = MKMapTypeSatellite;
}
if ([sender tag] == 2) {
self.mapView.mapType = MKMapTypeHybrid;
}
}
- (void)updateRegion
{
self.needUpdateRegion = NO;
CGRect boundingRect;
BOOL started = NO;
for (id <MKAnnotation> annotation in self.mapView.annotations) {
CGRect annotationRect = CGRectMake(annotation.coordinate.latitude, annotation.coordinate.longitude, 0, 0);
if (!started) {
started = YES;
boundingRect = annotationRect;
} else {
boundingRect = CGRectUnion(boundingRect, annotationRect);
}
}
if (started) {
boundingRect = CGRectInset(boundingRect, -0.2, -0.2);
if ((boundingRect.size.width < 20) && (boundingRect.size.height < 20)) {
MKCoordinateRegion region;
region.center.latitude = boundingRect.origin.x + boundingRect.size.width / 2;
region.center.longitude = boundingRect.origin.y + boundingRect.size.height / 2;
region.span.latitudeDelta = boundingRect.size.width;
region.span.longitudeDelta = boundingRect.size.height;
[self.mapView setRegion:region animated:YES];
}
}
}
- (void)parseGoogleJsonToObtainPointsForPolyline {
NSDictionary *polyline;
NSMutableArray *points = [[NSMutableArray alloc]init];;
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
NSArray *legs = [appDelegate.dataForMap objectForKey:#"legs"];
NSDictionary *firstZero =[legs objectAtIndex:0];
NSArray *steps = [firstZero objectForKey:#"steps"];
for (int i = 0; i < steps.count; i++) {
polyline = [steps[i] objectForKey:#"polyline"];
[points addObject:polyline[#"points"]];
NSLog(#"POINTS = %#", polyline[#"points"]);
self.path = [self decodePolyLine:points[i]];
}
NSLog(#"path = %#", self.path);
}
-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {
NSMutableString *encoded = [[NSMutableString alloc] initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:location];
}
return array;
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor redColor];
polylineView.lineWidth = 1.0;
return polylineView;
}
- (void)createMKpolylineAnnotation {
NSInteger numberOfSteps = self.path.count;
CLLocationCoordinate2D *coords = malloc(sizeof(CLLocationCoordinate2D) * numberOfSteps);
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [self.path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coords[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coords count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
#end
I used the AppDelegate to have the Json (I parsed it in another class)
Here is a tutorial how to add a polyline to a mapView. Hope this helps!
EDIT:
Unfortunately, the link provided above is now broken, and I am not able to find the tutorial referred to.
simple, just copy and paste my code and modify some variables
- (IBAction)traceRoute:(UIButton *)sender {
double latDouble = 39.7540615;
double lngDouble = -8.8059587;
// double latDouble = [self.sheetDetail.data.locationLat doubleValue];
// double lngDouble = [self.sheetDetail.data.locationLng doubleValue];
CLLocationCoordinate2D c2D = CLLocationCoordinate2DMake(latDouble, lngDouble);
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:c2D addressDictionary:nil];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:#"Mobile Edge"];
MKPlacemark *placemark2;
MKMapItem *mapItem2;
if(kIS_OS_8_OR_LATER) {
placemark2 = [[MKPlacemark alloc] initWithCoordinate:_userLoc addressDictionary:nil];
mapItem2 = [[MKMapItem alloc] initWithPlacemark:placemark2];
[mapItem2 setName:#"Me"];
} else {
placemark2 = [[MKPlacemark alloc] initWithCoordinate:_mapView.userLocation.coordinate addressDictionary:nil];
mapItem2 = [[MKMapItem alloc] initWithPlacemark:placemark2];
[mapItem2 setName:#"Me"];
}
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = mapItem2;
request.destination = mapItem;
request.requestsAlternateRoutes = NO;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle error
[[NSNotificationCenter defaultCenter] postNotificationName:#"finishedLocationRoute" object:nil];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: NSLocalizedString(#"Route error title", nil)
message: NSLocalizedString(#"Route error", nil)
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
} else {
for (MKRoute *route in response.routes)
{
//MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2];
//[self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint) andRoute:route];
[self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
//notifies parent menu
//[[NSNotificationCenter defaultCenter] postNotificationName:#"finishedLocationRoute" object:nil];
}
}];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay
{
if (![overlay isKindOfClass:[MKPolygon class]]) {
MKPolyline *route = overlay;
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
renderer.strokeColor = [UIColor blueColor];
renderer.lineWidth = 5.0;
return renderer;
} else {
return nil;
}
}
I am trying to display multiple annotations on my mapView from an array. The annotation coordinates are parsed from an XML file and stored in the array as [currentCall longitude] and [currentCall latitude]. My question is, what is the syntax for "calling" the array? (I don't know if that's how you say it). In another part of my application, I display the parsed XML results in a table and use "JointCAD *currentCall = [[xmlParser calls] objectAtIndex:indexPath.row];" to "call" the array. How do I do it for displaying my annotations? Everything else works fine except that little part.
Here is the implementation file:
#implementation SecondViewController
#synthesize mapView;
XMLParser *xmlParser;
-(IBAction)getlocation {
mapView.showsUserLocation = YES;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView commitAnimations];
}
-(IBAction)changeSeg:(id)sender {
if (segment.selectedSegmentIndex == 0) {
mapView.mapType = MKMapTypeStandard;
}
if (segment.selectedSegmentIndex == 1) {
mapView.mapType = MKMapTypeSatellite;
}
if (segment.selectedSegmentIndex == 2) {
mapView.mapType = MKMapTypeHybrid;
}
}
-(void)viewDidLoad {
JointCAD *currentCall = [[xmlParser calls] objectAtIndex:indexPath.row];
mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
[self.view insertSubview:mapView atIndex:0];
[super viewDidLoad];
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
[mapView setDelegate:self];
MKCoordinateRegion WCCCA = { {0.0, 0.0} , {0.0, 0.0} };
WCCCA.center.latitude = 45.53540820864449;
WCCCA.center.longitude = -122.86178648471832;
WCCCA.span.longitudeDelta = 0.02f;
WCCCA.span.latitudeDelta = 0.02f;
[mapView setRegion:WCCCA animated:YES];
Annotation *ann1 = [[Annotation alloc] init];
ann1.title = #"WCCCA";
ann1.subtitle = #"Washington County Consolidated Communications Agency";
ann1.coordinate = WCCCA.center;
[mapView addAnnotation: ann1];
MKCoordinateRegion CALL = { {0.0, 0.0} , {0.0, 0.0} };
CALL.center.latitude = [currentCall.latitude doubleValue];
CALL.center.longitude = [currentCall.longitude doubleValue];
CALL.span.longitudeDelta = 0.02f;
CALL.span.latitudeDelta = 0.02f;
[mapView setRegion:WCCCA animated:YES];
Annotation *ann2 = [[Annotation alloc] init];
ann2.title = [currentCall currentCallType];
ann2.subtitle = [currentCall location];
ann2.coordinate = CALL.center;
[mapView addAnnotation: ann1];
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
MKPinAnnotationView *MyPin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"current"];
MyPin.pinColor = MKPinAnnotationColorRed;
UIButton *advertButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[advertButton addTarget:self action:#selector(button:) forControlEvents:UIControlEventTouchUpInside];
MyPin.rightCalloutAccessoryView = advertButton;
MyPin.draggable = NO;
MyPin.highlighted = YES;
MyPin.animatesDrop=TRUE;
MyPin.canShowCallout = YES;
return MyPin;
}
#end
If I am understanding your code properly, you should be able to just iterate through your parsed XML (it appears that the output the from your xmlParser object is an NSArray) and add the annotations to the mapView within the loop.
You can use the C function CLLocationCoordinate2DMake() to create the coordinate data structure for your annotation.
NSArray *callsArray = [xmlParser calls];
for (JointCAD *call in callsArray) {
Annotation *ann = [[Annotation alloc] init];
ann.title = [call currentCallType];
ann.subtitle = [call location];
ann.coordinate = CLLocationCoordinate2DMake([call latitude], [call longitude]);
[mapView addAnnotation:ann];
}