Need to add a Fixed Overlay like on mapview in IOS - ios

I need to create a map view interface, which is something similar to the OLA Cabs Application in iOS. What I exactly wanna do is to fix an overlay on mapView and allow the user to scroll the map view across it. So that the overlay can be fixed at any location the User wants it to, I searched a lot about overlays, in iOS and MapKit, but couldn't make it possible. If some one can give me tips for achieving this I would be really grateful. Here is a snapshot of the screen
Here the annotation remains fixed and you can move the map view across it, So that when you stop the mapview, the overlay will be pointing to the new location, where you stopped

Click here to download demo...
Create a fix MKAnnotation and image view object to animating the location change effect in Map view.
#property (nonatomic, strong) CustomAnnotation *fixAnnotation;
#property (nonatomic, strong) UIImageView *annotationImage;
Add this code in viewDidLoad() method:
// Fix annotation
_fixAnnotation = [[CustomAnnotation alloc] initWithTitle:#"Fix annotation" subTitle:#"Location" detailURL:nil location:self.mapView.userLocation.coordinate];
[self.mapView addAnnotation:self.fixAnnotation];
// Annotation image.
CGFloat width = 64;
CGFloat height = 64;
CGFloat margiX = self.mapView.center.x - (width / 2);
CGFloat margiY = self.mapView.center.y - (height / 2) - 32;
// 32 is half size for navigationbar and status bar height to set exact location for image.
_annotationImage = [[UIImageView alloc] initWithFrame:CGRectMake(margiX, margiY, width, height)];
[self.annotationImage setImage:[UIImage imageNamed:#"mapannotation.png"]];
Now have to remove image when you drag a map view and add image which looks like an annotation. And after completion of that add annotation and remove image from Map View.
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
NSLog(#"Region will changed...");
[self.mapView removeAnnotation:self.fixAnnotation];
[self.mapView addSubview:self.annotationImage];
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
NSLog(#"Region did changed...");
[self.annotationImage removeFromSuperview];
CLLocationCoordinate2D centre = [mapView centerCoordinate];
self.fixAnnotation.coordinate = centre;
[self.mapView addAnnotation:self.fixAnnotation];
}

Its not an map annotation overlay, its a normal UIImageView which has been placed over MKMapView, and it always used to get the lat-long for the center point of the map.
Hope this would be an easy way to achieve your goal.
#Kampai has added the same code for you.

Related

Adding overlapping annotations to map

I have an array of coordinates and I already know how to add it on a map as annotations.
What I'd like to do now is the following:
each annotation should be a red circle (no pins) that represents a fixed radius of 1 Km around the coordinates. That means that if I zoom in or out the map, the circle should adjusts itself to always represent a 1 Km radius;
if two or more circles overlaps, their color intensity should increase. For example, three or four overlapping circles will produce a solid red circle.
That's all. I have no idea where to start with this, so any help will be greatly appreciated.
For starter you can use below code but you will have to tweak it little to make it of your use:
in .h file confirm to MKMapViewDelegate
#interface MapViewController : UIViewController <MKMapViewDelegate>
Then,
in "viewDidLoad"
CLLocationCoordinate2D center = {X cordinate, Y cordinate};
//--> Add overlay
MKCircle *mCircle = [MKCircle circleWithCenterCoordinate:center radius:1000]; //set radius as per your need
[self.mapView addOverlay:mCircle];
Then,
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
MKCircleView *cirView = [[MKCircleView alloc] initWithOverlay:overlay];
[cirView setFillColor:[UIColor redColor]];
[cirView setStrokeColor:[UIColor blackColor]];
[cirView setAlpha:0.3f];
return cirView;
}
I think this should get you started.

PopOver frame issue in iPhone SDK

I display a popover in map view as follows:
But when i rotate the device, It shows Like:
as you see it covers the annotation instead of showing just beside the annotation.
My code is as as shown below:
CGPoint annotationPoint = [mapView convertCoordinate:aView.annotation.coordinate toPointToView:mapView];
float boxDY=annotationPoint.y;
float boxDX=annotationPoint.x;
CGRect box = CGRectMake(boxDX,boxDY,5,5);
UILabel *displayLabel = [[UILabel alloc] initWithFrame:box];
[popView presentPopoverFromRect:displayLabel.frame inView:mapView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[displayLabel release];
Help me to solve this problem.
You can try to override the following method (declared in UIViewcontroller.h) :
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
You'll probably need to save the state of your viewController (like isPopoverPresented, which annotation etc.) and update the popover's rect accordingly.

New foursquare venue detail map

I really love the way foursquare designed venue detail view. Especially the map with venue location in the "header" of view ... How was it done? Details are obviously some uiscrollview (maybe uitableview?) and behind it (in the header) there is a map so when you scroll up the map is beeing uncovered as the scroll view bounces... does anyone has an idea how to do this?
Here's the way I manage to reproduce it:-
You need a UIViewController with a UIScrollView as its view. Then, the content of the UIView you add to your scrollview should look like this :-
- The frame of the MKMapView have a negative y position. In this case, we can only see 100pts of the maps in the default state (before dragging).
- You need to disable zooming and scrolling on your MKMapView instance.
Then, the trick is to move down the centerCoordinate of the MKMapView when you drag down, and adjust its center position.
For that, we compute how much 1point represent as a delta latitude so that we know how much the center coordinate of the map should be moved when being dragged of x points on the screen :-
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView* scrollView = (UIScrollView*)self.view;
[scrollView addSubview:contentView];
scrollView.contentSize = contentView.frame.size;
scrollView.delegate = self;
center = CLLocationCoordinate2DMake(43.6010, 7.0774);
mapView.region = MKCoordinateRegionMakeWithDistance(center, 1000, 1000);
mapView.centerCoordinate = center;
//We compute how much latitude represent 1point.
//so that we know how much the center coordinate of the map should be moved
//when being dragged.
CLLocationCoordinate2D referencePosition = [mapView convertPoint:CGPointMake(0, 0) toCoordinateFromView:mapView];
CLLocationCoordinate2D referencePosition2 = [mapView convertPoint:CGPointMake(0, 100) toCoordinateFromView:mapView];
deltaLatFor1px = (referencePosition2.latitude - referencePosition.latitude)/100;
}
Once those properties are initialized, we need to implement the behavior of the UIScrollViewDelegate. When we drag, we convert the move expressed in points to a latitude. And then, we move the center of the map using the half of this value.
- (void)scrollViewDidScroll:(UIScrollView *)theScrollView {
CGFloat y = theScrollView.contentOffset.y;
// did we drag ?
if (y<0) {
//we moved y pixels down, how much latitude is that ?
double deltaLat = y*deltaLatFor1px;
//Move the center coordinate accordingly
CLLocationCoordinate2D newCenter = CLLocationCoordinate2DMake(center.latitude-deltaLat/2, center.longitude);
mapView.centerCoordinate = newCenter;
}
}
You get the same behavior as the foursquare app (but better: in the foursquare app, the maps recenter tends to jump, here, changing the center is done smoothly).
The example above is nice. If you need more help, I think they're using something very similar to RBParallaxTableViewController. https://github.com/Rheeseyb/RBParallaxTableViewController
It's essentially the same effect that Path uses for its header photo.
Yonel's answer is nice, but I found a problem as I have a pin at the center of the map. Because the negative Y, the point is hidden under my UINavigationBar.
Then, I didn't set the Negative Y, and I correct my mapView.frame according the scroll offset.
My mapView is 320 x 160
_mapView.frame = CGRectMake(0, 160, 320, -160+y);
Hope this helps someone.

iOS SDK Mapview Annotation callout redraw error

I'm trying to add the distance from the user's position to a selected annotation's subtitle in a mapview. The mechanics of it are working, but the actual callout gets messed up the first time it's displayed. There appears to be a redraw problem.
Subsequent taps on the pin show the correct layout.
Here's the relevant code:
// called when selecting annotations
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
MKPointAnnotation *selectedAnnotation = view.annotation;
//attempt to add distance on annotation
CLLocation *pointALocation = [[CLLocation alloc]
initWithLatitude:selectedAnnotation.coordinate.latitude
longitude:selectedAnnotation.coordinate.longitude];
float distanceMeters = [pointALocation distanceFromLocation:locationManager.location];
//for sending info to detail
myPinTitle = selectedAnnotation.title;
[selectedAnnotation setSubtitle:[NSString stringWithFormat:#"%.2f miles away", (distanceMeters / 1609.344)]];
}
I've tried calling [view setNeedsDisplay], but to no avail.
Thanks in advance for your help.
The Solution that Worked
Here's the solution I finally came up with. It seems to work.
I edited out the duplicate code from the didSelectAnnotationView method, above, and came up with:
//called when user location changes
- (void)updatePinsDistance
{
for (int x=0; x< [[mapView annotations]count]; x++) {
MKPointAnnotation *thisPin =[[mapView annotations] objectAtIndex:x];
//attempt to add distance on annotation
CLLocation *pointALocation = [[CLLocation alloc]
initWithLatitude:thisPin.coordinate.latitude
longitude:thisPin.coordinate.longitude];
float distanceMeters = [pointALocation distanceFromLocation:locationManager.location];
NSString *distanceMiles = [NSString stringWithFormat:#"%.2f miles from you",
(distanceMeters / 1609.344)];
[thisPin setSubtitle:distanceMiles];
}
}
You should set your subtitle in another place than didSelectAnnotationView. Actually all annotationViews should have their title and subtitle set before they are returned by the mapView:viewForAnnotation: method.
The fact that you set a long subtitle certainly explains that the callout is not the right size. The size must be calculated before the didSelectAnnotationView is called.

iOS MapKit Annotation, not showing correct location

I using a custom image for my mapkit annotation. But the main problem it seems that I am running into in using a custom image, is that when zoomed out, the annotation is not in the correct point on the map, and ONLY until I zoom in all the way down, will it show the annotation point in the correct place. It seems that when I use a regular pin MKPinAnnotationView, it works normally, as with the pin being in the correct place zoomed in or out, thanks in advance for anyone that can help.
The code I have used is as follows:
- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"welcome into the map view annotation");
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView *pprMapNote = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"pprMapNote"];
pprMapNote.image = [UIImage imageNamed:[NSString stringWithFormat:#"GPS_note.png"]];
pprMapNote.canShowCallout = YES;
pprMapNote.centerOffset = CGPointMake(-21,-60);
pprMapNote.calloutOffset = CGPointMake(0, 0);
//[pprMapNote addSubview:pprMapNoteImg];
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:#selector(showDetail)
forControlEvents:UIControlEventTouchUpInside];
pprMapNote.rightCalloutAccessoryView = rightButton;
//remember to write in conditional for the different icons that should be loaded based on location
UIImageView *pprNoteLocIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"loc_icon_casino.png"]];
pprMapNote.leftCalloutAccessoryView = pprNoteLocIcon;
[pprNoteLocIcon release];
return pprMapNote;
}
You are setting the centerOffset of the annotation view.
Note that this offset is not scaled with the zoom level. The further you zoom out, the further the image will appear from the coordinate.
In the default MKPinAnnotationView, the centerOffset is left at the default of 0,0 and the pin image is designed such that the bottom point of the pin is on the coordinate. So as you zoom further out, the pin image seems to grow relative to the map under it but the bottom of the pin is still pointing to the coordinate.
You need to either adjust the centerOffset based on your image or modify your image so you don't need to set centerOffset. Or just try commenting out the setting of centerOffset--maybe you don't need it.
Some other unrelated items:
You have a memory leak for the pprMapNote alloc+init (add an autorelease)
You should be using dequeueReusableAnnotationViewWithIdentifier to allow for annotation view re-use.
Instead of using addTarget to call your own method for the callout button press, it's much better to use the map view's own delegate method calloutAccessoryControlTapped
See this answer for an example of the above three points.
The Pin is drawn in a separate view, so it will not zoom based on the status of your view.
You have to set the size of your custom Pin image manually. This can easily be done using the centerOffset. For most cases it is enough to set the height of the frame to half the size of the image. The image is fully filled in the frame, so you can easily use this frame size(height).
aView.image = [UIImage imageNamed ... ];
aView.centerOffset = CGPointMake(0,-aView.frame.size.height*0.5);

Resources