I am new to iphone development.I am creating a map application. I have created tool bar with a button below the mapview.When i click the button it should display a alert view showing the current location and asking to update. on clicking OK in alert view should open my map with the current location and CANCEL to close the alert view.The button action is defined in the method
-(IBAction) gosearch : (id) sender{
NSLog(#"inside go search");
}
What should i do to achieve my task.I have added core location framework.But i dont know how to proceed.I saw some inbuilt methods to be used from this link http://iappdevs.blog.co.in/2008/12/06/get-current-location-sample-example-iphone-programming/ but i am not able to implement it.Please guide me.Thanks.
the MapKit component MKMapView display the current position on its own, you don't have to do anything.
Actually, internally, it instantiates a CLLocationManager and starts updating location on it to get live position events. when it gets those positions, it displays them as a blue dot, with circles with various radius to indicate the accuracy, but this is done automatically.
To trigger the display of the current position on the MKMapView, just set the showsUserLocation to YES on your MKMapView instance and you'll get this this blue dot being displayed and updated in real time.
Where does your problem start - have you got a core location delegate that gets location updates? You need to start core location using these methods:
In applicationdidfinishingLauncing()
{
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self; // Tells the location manager to send updates to this object
[locationManager startUpdatingLocation];
This will get core location to call you back as it gets updates on the location, starting with a rough location but further updates should get you a more accurate focus.
Related
I would like to add an infoWindow when the user taps their current location (blue dot) in the Google Maps API V1.3 for iOS.
I can get infoWindows on other markers but not to display above the users location. Any help would be appreciated. Thanks!
As an alternative option, could you add a marker with a transparent icon at the user's current location?
You could use KVO to move the marker whenever the map view's myLocation value changes.
You can see some sample code for how to add an observer here (but instead of moving the camera, you could move your invisible marker):
about positioning myself,some problems
when you go with the the 'default' user location, you can't. Because it isn't a real marker, the callbacks aren't fired.
What I did in our case is that I set showsMyLocation=NO but I rolled my own location. I added another marker and used a CLLocationManager to position it according to THAT position..
So in pseudocode
- viewDidLoad
map.showsUserLocation=NO;
locationManager = [CLLocationManager new];
locationManager.delegate = self;
}
- locationManager:didUpdateUserLocation:newLoc {
if(!annotation) {
annotation = [GMSMarker new];
annotation.map = map;
}
annotation.position = newLoc;
}
=> own annotation that you can treat like any other marker!
I am developing a iPhone app running on iOS5, and am unable to set up geofences when I call the startMonitoringForRegion:desiredAccuracy: method on click of a button.
It works fine in the simulator when I print out the regions in monitoredRegions, but when running on an actual iPhone 4, the monitoredRegions is always empty. Expectedly, the didEnterRegion: and didExitRegion: methods are not called as well.
Another puzzling fact is that on BOTH the simulator and the iPhone 4 device, the CLLocationManagerDelegate method didStartMonitoringForRegion: is never called as well.
Would appreciate some help here, thank you!
EDIT:
this is method that I call on click of a button:
-(void) queueGeofence: (CLLocationCoordinate2D)selectedBranch userCoordinate:(CLLocationCoordinate2D)userCoordinate radius: (CLLocationDegrees)radius {
geofence = [[CLRegion alloc] initCircularRegionWithCenter:selectedBranch radius:radius identifier:#"geofence"];
CLLocationAccuracy acc = kCLLocationAccuracyNearestTenMeters;
[locationManager startMonitoringForRegion:geofence desiredAccuracy:acc];
[CLLocationManager regionMonitoringEnabled];
NSLog([CLLocationManager regionMonitoringEnabled] ? #"regionMonitoringEnabled:Yes" : #"regionMonitoringEnabled:No");
NSLog([CLLocationManager regionMonitoringAvailable] ? #"regionMonitoringAvailable:Yes" : #"regionMonitoringAvailable:No");
NSLog(#"LOCATIONMANAGER monitored regions: %#", [locationManager monitoredRegions]});
}
Region monitoring is both enabled and available, but monitoredRegions is still giving me back nothing.
If you look in CLLocationManager.h, the comments in the header for startMonitoringForRegion:desiredAccuracy: state that
If a region with the same identifier is already being monitored for this application, it
will be removed from monitoring. This is done asynchronously and may not be immediately reflected in monitoredRegions.
Therefore, you shouldn't necessarily expect that [locationManager monitoredRegions] would include your newly added region since it is added asynchronously.
Are you implementing the delegate method for locationManager:monitoringDidFailForRegion:withError:? Maybe that's getting called instead of locationManager:didStartMonitoringForRegion:. Also note that a region with the same identifier as an existing region will get removed, so you might be running into some unexpected problems because you're reusing "geofence" as your identifier.
First of all, you should be sure, that your app has a permission to use LocationManager. Check it when you alloc your manager.
[CLLocationManager authorizationStatus];
I had the same trouble when start app and decline a permission. And after deleting and rebuilding app. I had a flag, that user didn't accept it. Turn it on.
If you are just going by your NSLog, it probably isn't going to work. [locationManager monitoredRegions] returns an NSSet of CLRegions. They won't display to your log that way. Try this:
NSSet *setOfRegions = [locationManager monitoredRegions];
for (CLRegion *region in setOfRegions) {
NSLog (#"region info: %#", region);
}
In my iPhone application, I want to drop a pin at my current location using mapView and I also need to move another pin or a ball as my position changes. How can I do this?
To display user location, just add :
mapView.showsUserLocation = YES;
To get it, use the method userLocation which gives you a MKUserLocation.
You can then add a id<MKAnnotation> object with addAnnotation method to display another pin.
Update #5 I guess it's bounty time. 100+ views and no one's taken a stab, even with the code sample I've posted. How about some reputation points!
Update #4This is a pretty complicated question, so I created a new tab based project which just includes the parts of my app I'm having trouble with here. You can download it from: http://www.servinitup.net/CustomCalloutAnnotation.zip
Feel free to open it up (need to add your own bundle identifier to run it on your phone) and play around with it, and see if you can get that darned callout annotation to move with the pin!
Update #3 Tried making setAnnotation a public method of the tutorial's CalloutMapAnnotationView and calling that directly. Didn't have any luck. Despite little oddities that occurred, the only thing that moved was the little triangle portion of the callout. I could not get the entire callout to move.
Update #2 Still not much luck, but have now been looking for ways to programmatically create a "pinch to zoom" and then undo it immediately, so the user never sees a change. Hoping that doing this programmatically will have the same effect as doing it manually, and the callout annotation will pop back to it's parent. Any ideas?
Update #1 After playing around here's where I've gotten:
- replaced self.calloutAnnotation.coordinate = coords; with self.calloutAnnotation.latitude = coords.latitude;self.calloutAnnotation.longitude = coords.longitude;
- With that changed, if I slightly pinch the map to zoom in or out after the pin has been updated, the callout annotation animates to the correct position, right over the pin.
So now I need to figure out how to get this to happen without the user having to actually pinch to zoom.
Original Post
I, along with other SO users, are using this awesome solution to create a custom callout annotation:
http://blog.asolutions.com/2010/09/building-custom-map-annotation-callouts-part-1/
When you use a standard callout (annotationview.canShowCallout = true) and the pin moves around the screen as the location is updated, the standard callout tracks right along with the pin, as if they're locked together.
When using the custom callout solution above, when my pin moves around after location updates, the callout annotation stays in it's original location. Of course, I'd like to mimic the iOS standard and have the custom callout annotation track along with the pin.
Here's the code I have so far, that's successfully moving the annotation view, but not the custom callout annotation view:
/* core location broadcasts a notification, and my view controller listens to that notification and calls locationManagerDidFindLocation */
- (void)locationManagerDidFindLocation:(NSNotification *)notif {
CLLocation *location = [notif.userInfo objectForKey:#"location"];
CLLocationCoordinate2D coords = [location coordinate];
MKCoordinateSpan span = MKCoordinateSpanMake((5/69), (5/69));
MKCoordinateRegion region = {coords, span};
// if we don't have a current location yet, create one, place it on the map, and adjust the map's region
// otherwise, update the annotation placement and map position in a smooth animation
if (self.currentLocationAnnotation == nil) {
self.currentLocationAnnotation = [[CurrentLocationAnnotation alloc] initWithCoordinate:coords andTitle:#"My Title" andSubtitle:#"My subtitle"];
[self.mapView addAnnotation:self.currentLocationAnnotation];
[self.mapView setRegion:region animated:true];
[self.mapView regionThatFits:region];
} else {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.45];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
// this moves my annotation view perfectly
self.currentLocationAnnotation.coordinate = coords;
// ******* this is where my problem is
// ******* this custom callout annotation view stays
// ******* in it's original place, even though it's
// ******* parent annotation view is moving around the screen
self.calloutAnnotation.coordinate = coords;
[self.mapView setRegion:region animated:true];
[self.mapView regionThatFits:region];
[UIView commitAnimations];
}
}
I created a project based on your CalloutMapAnnotationView demonstrating a IB based solution. Arrow keys animate motion of the location annotation and it's callout annotation. The callout now also automatically resizes based on the supplied contentView, and the view is loaded from a separate nib. Good luck!
https://github.com/jacobjennings/JJMapCallout
I know you aren't going to like this answer, but it works. The sample you linked to just draws a custom image in the overlay through the most difficult way possible (drawRect:). Have you considered rendering your overlay once into a UIImage, and just setting the image property on a very simple MKAnnotationView? Even if you need to change the content periodically, like updating the number of friends at a bar, you can redraw the image when the change occurs and update the appropriate MKAnnotationView.
I review your code and my recommendation is to create a new custom MKAnnotationView and encapsulate on it both views (the pin and the callout).
But for your current code consider read the approved response this question: MKMapView moving Annotations Automatically - animate them?
Cheers.
My app knows the current user position (CoreLocation.framework).
As soon as the user opens a new MapView his iPhone starts searching for the current position again.
Is it possible to skip that or to change the first user position for mkMapView?
Edit:
Is it possible to overwrite MKMapView and use an other LocationManager?
Yes, it is possible to have a separate location manager object and assign its value to the mapview (BTW, I'm using '=' below as list prefix to prevent the SO code-formatter from borking).
= In your UIViewController maintain two separate properties: one to a MKMapView and one to a CLLocationManager.
= Create a XIB file with the MKMapView and any other window chrome you want. Connect the outlets to the controller propeties. Make sure MKMapView does NOT follow user location.
= Have the UIViewController implement the CLLocationManagerDelegate protocol--especially the locationManager:didUpdateToLocation:fromLocation: method which will be called whenever a new location value is available. We'll be setting the controller as the delegate for the location manager.
= In the viewController's loadView method, load the NIB with the MKMapView in it. To give user feedback you may want to put up a UIActivityIndicatorView spinner and set it to startAnimating. Then you start with:
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
self.locationManager.distanceFilter = 10; // or whatever
[self.locationManager startUpdatingLocation];
= In locationManager:didUpdateToLocation:fromLocation: check to see if the event was updated since the last N seconds. Then tell the location manager to stop updating, the spinner to stop animating, and get the lat/long data and assign it to the map view along with a view span and region so it zooms and centers to the right place.
= Now here's the tricky part: the blue marble 'throbber' is a feature of the mapview tracking user location. You'll have to momentarily 'fake it' until the real one kicks in (or just use a separate marker for the current location and maintain its position yourself). Personally I'd go with the blue marble that the user is familiar with.
= To make it so it shows right at startup you will need to create a custom MKAnnotationView with just the blue marble graphic added at the location returned by the location manager. This means taking a snapshot of a Mapview with the location showing, then photoshopping just the blue marble out and using it as the image for a custom annotation view.
= If you want it to actively follow the map, you can enable the userlocation tracking of the mapview and when it gets the actual data, you hide your previously set marker and let the mapview do the updating. The other option is to allow the existing location manager to continue receiving updates every second or so and update the position of the blue marble annotation yourself.
= To let the mapview's own userLocation do the updating add to viewDidLoad:
[self.map.userLocation addObserver:self
forKeyPath:#"location"
options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)
context:NULL];
self.map.showsUserLocation = YES; // starts updating user location
= Implement observeValueForKeyPath. It gets called when the location attribute of the mapview's userlocation has a value:
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([self.map isUserLocationVisible]) {
[self.locationManager stopUpdatingLocation];
self.ownBlueMarble.hidden = YES;
}
// The current location is in self.map.userLocation.coordinate
}
= To avoid the warm-up delay in showing current location, keep a reference to the viewController containing the map and the location manager so it doesn't go away (it's a bit of a memory hog but if you release it you'll have to wait again until MapView loads the tiles and is ready to go).
= In viewWillLoad you can stuff the last known location into the custom bluemarble annotation and show it. Toggle on/off the userLocation tracking and when you get the notification the same hide-the-annotation-show-the-real-marble trick will work. The mapview's own location manager kicks in and when it has the data, you can make your annotation marker disappear.
= You might want to implement the viewController's viewWillDisappear method and manually turn off userLocation tracking on the mapview so it's off by default the next time the view is brought up. You'll also want to get the last known userLocation and save it for the next get-go. That way, you can do all the positioning marker-juggling in the viewWillAppear method and not have to worry about userLocation interfering until you're ready for it.
Good luck.
In your controller:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CLLocationCoordinate2D coord = {latitude: 37.423617, longitude: -122.220154};
MKCoordinateSpan span = {latitudeDelta: 1, longitudeDelta: 1};
MKCoordinateRegion region = {coord, span};
[mapView setRegion:region];
}
When map appears it's going to be centered close to Palo Alto
Try setting the showUserLocation property to false on initialisation and then restore the region the map view previously had (you will obviously have to store this before the previous map is destroyed).
Is this what you wanted?
You don't need to use another Location Manager, you can add whatever points you want to the map and update them via whatever other logic you want.
Let's say you had a socket connection to a remote control car, and that car send back socket data containing geo-location information in the payload. You could parse that out, and update the location of the thumbnail on your map in real time. The "userLocation" property is not needed for that, but you could show it if you wanted to.
The location of the user is read-only, you can use it or not. That doesn't mean you need another location manager to do anything you might need to do. It sounds like your app doesn't really need that feature, but I could be misunderstanding your question.