I am adding annotations as hardcoded values into the method
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
CLLocationCoordinate2D coords1;
coords1.latitude = 40.579754;
coords1.longitude = -120.1303229;
MKPointAnnotation *annotationPoint1 = [[MKPointAnnotation alloc] init];
annotationPoint1.coordinate = coords1;
annotationPoint1.title = #"TJ11234";
annotationPoint1.subtitle = #"Power Failure \n Start Time:12hrs 30min \n End Time:14hrs ";
[self.mapView addAnnotation:annotationPoint1];
with values of lats and longitude hardcode intially its loading fine, but when I go to another page and come back to the page the annotations are not loading. What should I do to correct it?
mapView:didUpdateUserLocation: is called whenever a new location update is received by the map view. Check the documentation.
If you want to set annotation when your map is shown, you can place your code in viewDidAppear or similar.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated]
CLLocationCoordinate2D coords1;
coords1.latitude = 40.579754;
coords1.longitude = -120.1303229;
MKPointAnnotation *annotationPoint1 = [[MKPointAnnotation alloc] init];
annotationPoint1.coordinate = coords1;
annotationPoint1.title = #"TJ11234";
annotationPoint1.subtitle = #"Power Failure \n Start Time:12hrs 30min \n End Time:14hrs ";
[self.mapView addAnnotation:annotationPoint1];
}
Hope this helps.
Related
I have the following method defined in a view controller class. At the last line of this code I declare the draggable attribute to be set to YES, but surprisingly it doesn't work when in the app.
What may cause this?
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
CLLocationDegrees latitude = -33.861;
CLLocationDegrees longitude = 151.20;
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(latitude,longitude);
marker.map = _mapView;
marker.draggable = YES;
}
You need to long push the marker then you can drag it.
I am trying to track user's route and drawing lines of the route, but the addOverlay only gives me correct points but no connection between each point.
-(void)viewWillAppear:(BOOL)animated{
self.trackPointArray = [[NSMutableArray alloc] init];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(CLLocation *)userLocation
{
[self.trackPointArray addObject:userLocation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 1000, 1000);
[self.myMapView setRegion:[self.myMapView regionThatFits:region] animated:YES];
NSInteger stepsNumber = self.trackPointArray.count;
CLLocationCoordinate2D coordinates[stepsNumber];
for (NSInteger index = 0; index < stepsNumber; index++) {
CLLocation *location = [self.trackPointArray objectAtIndex:index];
coordinates[index] = [location coordinate];
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:stepsNumber];
[self.myMapView addOverlay:polyLine];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)myMapView rendererForOverlay:(id<MKOverlay>)overlay
{
MKPolylineRenderer *polylineRenderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
polylineRenderer.lineWidth = 4.0f;
polylineRenderer.strokeColor = [UIColor redColor];
return polylineRenderer;
}
The userLocation object the map view passes to the didUpdateUserLocation delegate method is the same object every time.
The coordinate inside the object may be different at each moment but each call to the delegate method always points to the same container object.
Specifically, it always points to the same object that the map view's userLocation property points to (mapView.userLocation). You can see this if you NSLog userLocation and mapView.userLocation and notice their memory addresses are the same each time.
For this reason, when the code does this:
[self.trackPointArray addObject:userLocation];
it just adds the same object reference to the array multiple times.
Later, when the code loops through the trackPointArray array, each call to [location coordinate] returns the same coordinate every time because location always points to the same object (mapView.userLocation) and the coordinate does not change during the loop.
So each time the delegate method is called, a polyline is created with N coordinates (all the same) which ends up drawing a "dot".
The reason you see multiple dots is because the code is not removing previous overlays.
To fix all this, one easy way is to create a new CLLocation instance each time you want to add the updated coordinates:
CLLocation *tpLocation = [[CLLocation alloc]
initWithLatitude:userLocation.coordinate.latitude
longitude:userLocation.coordinate.longitude];
[self.trackPointArray addObject:tpLocation];
Additionally, you should remove the previous overlay before adding the updated line. You won't notice the previous lines if you don't do this but they'll be there using up memory and performance:
[self.myMapView removeOverlays:self.myMapView.overlays];
[self.myMapView addOverlay:polyLine];
Im trying to load annotation point into mapview in which i have the seperate array for latitude and a seperate array for longitude here is my code
- (void)viewDidLoad
{
[super viewDidLoad];
delegate=[[UIApplication sharedApplication]delegate];
delegate.arrForLat=[[NSMutablearray alloc]initwithobjects:#"33.930216",#"33.939788",#"33.9272",#"33.902237"];
delegate.arrForLon=[[NSMutablearray alloc]initwithobjects:#"-118.050392",#"-118.076549",#"-118.065817",#"-118.081733"];
for (int i=0 ; i< delegate.arrForLat.count;i++)
{
annotationCoord.latitude = [[delegate.arrForLat objectAtIndex:i] doubleValue];
annotationCoord.longitude = [[delegate.arrForLng objectAtIndex:i] doubleValue];
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
[MapView addAnnotation:annotationPoint];
}
}
Now i get only 1 annotation point in mapview but i have 4 coordinates.I don't know what mistake i have done.
Ah, I think I see it. You only have one annotationCoord. On the first trip through the loop you set its lat and long to (33.930216,-118.050392) and create a new object called annotationPoint point its coordinate attribute to your annotationCoord. Then on the next time through the loop you edit annotationCoord by giving it new coordinates. But it's still the same annotationCoord and the annotation you added to the map is still using it, now with the new coordinates.
So the solution is to make a new CLLocationCoordinate2D each time through the loop.
iPhone newbie is here coming from Java. So my objective at this stage is to allow the user to 'drop a pin' on the map. My initialization of the map looks like this:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"your view did load, I'm going to initizlie the map by your location");
CLLocationCoordinate2D location = theMap.userLocation.coordinate;
NSLog(#"Location found from Map: %f %f",location.latitude,location.longitude);
MKCoordinateRegion region;
MKCoordinateSpan span;
NSLog(#"coordinates: %f %f",location.latitude,location.longitude);
if (TARGET_IPHONE_SIMULATOR) {
NSLog(#"You're using the simulator:");
location.latitude = 40.8761620;
location.longitude = -73.782596;
} else {
location.latitude = theMap.userLocation.location.coordinate.latitude;
location.longitude = theMap.userLocation.location.coordinate.longitude;
}
span.latitudeDelta = 0.001;
span.longitudeDelta = 0.002;
region.span = span;
region.center = location;
[theMap setRegion:region animated:YES];
[theMap regionThatFits:region];
[theMap setMapType:MKMapTypeSatellite];
[theMap setZoomEnabled:YES];
[theMap setScrollEnabled:YES];
[theMap setShowsUserLocation:YES];
}
For the requested pin drop I have
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation {
MKPinAnnotationView *pinView = nil;
if (annotation != theMap.userLocation) {
static NSString *defaultPinID = #"aPin";
pinView = (MKPinAnnotationView *)[theMap dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if (pinView == nil)
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
} else {
}
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
return pinView;
}
I'm not sure I fully understand how this map (theMap) works for pins in viewForAnnotation? I mean, what action the user does will activate the viewForAnnotation method? This code doesn't work and I'm not sure why.
I'm using the simulator so I'm not sure if there's a button I should press or Alt click it?
I'm not sure I fully understand how this map (theMap) works for pins in viewForAnnotation?
MKPinAnnotationView is just another kind of annotation view -- that is, you add an annotation (an object conforming to the MKAnnotation protocol) to the map. When the map wants to display the annotation (maybe because the user scrolled the map so that the annotation is in view), it asks you for a view to use to represent the annotation. At that point, your mapView:viewForAnnotation: method can fetch or create a pin annotation view and return that. The user doesn't do anything directly to trigger mapView:viewForAnnotation:, except for scrolling or zooming.
If you want to the user to be able to drop a pin, that's a different thing. You'll need to provide a view (possibly even a MKPinAnnotationView) that they can drag around. When they indicate that they want to drop the pin (perhaps by lifting their finger), you remove the view and add an appropriate annotation at that point. Then the map view will ask you for a view to represent the annotation by calling its delegate's mapView:viewForAnnotation: method.
This code doesn't work and I'm not sure why.
Have you added any annotations to the map? If so, are you looking at the part of the map where they should be displayed?
I'm guessing that you're looking at the animatesDrop property and expecting it to do the entire user pin-dropping interaction. It doesn't do that. Setting that property to YES merely animates the pin as it appears on the map.
ok, after a while, I understood what went wrong:
theMap.delegate = (id) self;
in the constructor was missing. Once I did that any action by end user will activate other methods (protocols) of the map.
I have a tab on the RootViewController.m. The tab has 2 buttons. The first button upon click will go to CorpViewcontroller which has the mapView on it. When I click on the first button on the first try, the map is blank with google label on the bottom. I have to click back then click on the button again then the map show up. Is it possible to always show the map on the first button click?
My rootViewController.m to go to the second screen:
[self.navigationController pushViewController:self.corpController animated:YES];
The second screen called corpViewController has the following code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Set Remote Location";
self.jsonData = [[NSMutableData alloc] init];
mapView.showsUserLocation = YES;
//Setup the double tap gesture for getting the remote location..
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleGesture:)];
tgr.numberOfTapsRequired = 2;
tgr.numberOfTouchesRequired = 1;
[mapView addGestureRecognizer:tgr];
mapView.delegate = self;
NSLog(#"viewDidLoad done");
}
- (void)viewWillAppear:(BOOL)animated {
NSLog(#"viewWillAppear");
appDelegate = (NBSAppDelegate *)[[UIApplication sharedApplication] delegate];
double curLat = [appDelegate.curLat doubleValue];
MKUserLocation *userLocation = mapView.userLocation;
double miles = 10.0;
double scalingFactor = ABS( (cos(2 * M_PI * curLat / 360.0) ));
MKCoordinateSpan span;
span.latitudeDelta = miles/69.0;
span.longitudeDelta = miles/(scalingFactor * 69.0);
MKCoordinateRegion region2;
region2.span = span;
region2.center = userLocation.coordinate;
[mapView setRegion:region2 animated:YES];
NSLog(#"viewWillAppear done..");
}
Please Advise.
Thank you
Are you initializing the MapView in the viewDidLoad method in your view controller?
If so, try moving it to the viewDidAppear method. That worked for me.
In viewDidLoad you are setting showsUserLocation to YES and in viewWillAppear, you are zooming into the mapView.userLocation coordinate.
The userLocation property isn't usually ready with a valid coordinate immediately after setting showsUserLocation to YES.
The first time you show the view controller, it's still invalid and you are zooming into the coordinate 0,0.
By the time you show the view controller a second time, the user location has been obtained and the coordinate is valid.
Instead of zooming into the user location in viewWillAppear, do it in the delegate method mapView:didUpdateUserLocation: which the map view calls when it gets a user location update.
In addition, you also probably want to move the mapView.showsUserLocation = YES; to viewWillAppear and in viewWillDisappear, set it to NO. This way, the map view will zoom in to the user location every time the view controller is shown instead of just the first time.
An unrelated point is that to zoom in to a specific distance, it's much easier to use the MKCoordinateRegionMakeWithDistance function instead of trying to convert miles to degrees yourself.
Here's an example of the changes suggested in corpViewController:
- (void)viewWillAppear:(BOOL)animated
{
//move this from viewDidLoad to here...
mapView.showsUserLocation = YES;
}
-(void)viewWillDisappear:(BOOL)animated
{
mapView.showsUserLocation = NO;
}
-(void)mapView:(MKMapView *)mv didUpdateUserLocation:(MKUserLocation *)userLocation
//Changed the **internal** parameter name from mapView to mv
//to avoid a compiler warning about it hiding instance var with same name.
//It's better to use the passed parameter variable anyway.
{
NSLog(#"didUpdateUserLocation");
double miles = 10.0;
//Instead of manually calculating span from miles to degrees,
//use MKCoordinateRegionMakeWithDistance function...
//Just need to convert miles to meters.
CLLocationDistance meters = miles * 1609.344;
MKCoordinateRegion region2 = MKCoordinateRegionMakeWithDistance
(userLocation.coordinate, meters, meters);
[mv setRegion:region2 animated:YES];
}