I have a mapView with 2 circles. When I try to customize the large one the small one seems to follow the large one. For example if I customize the fill color for the large one the smaller one gets the same color. How do I make the smaller one a different color? Note: I use reusable identifiers. Thank you.. this is my working code but when i try to edit my smaller circle, the one with radius 100 it doesn't. note: this is my WORKING code as anything else i tried it failed.
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay {
static NSString *CircleOverlayIdentifier = #"Circle";
_mapView.delegate = self;
if ([overlay isKindOfClass:[CircleOverlay class]]) {
CircleOverlay *circleOverlay = (CircleOverlay *)overlay;
MKCircleView *annotationView =
(MKCircleView *)[mapView dequeueReusableAnnotationViewWithIdentifier:CircleOverlayIdentifier];
if (!annotationView) {
MKCircle *circle = [MKCircle
circleWithCenterCoordinate:circleOverlay.coordinate
radius:circleOverlay.radius];
annotationView = [[MKCircleView alloc] initWithCircle:circle];
//this one
}
if (overlay == self.targetOverlay) {
//adjustable
annotationView.fillColor = [UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:0.3f];
annotationView.strokeColor = [UIColor redColor];
annotationView.lineWidth = 1.0f;
} else {
//fixed
annotationView.fillColor = [UIColor colorWithWhite:0.3f alpha:0.3f];
annotationView.strokeColor = [UIColor purpleColor];
annotationView.lineWidth = 2.0f;
}
return annotationView;
}
return nil;
}
- (void)configureOverlay {
if (self.location) {
[self.mapView removeAnnotations:[self.mapView annotations]];
[self.mapView removeOverlays:[self.mapView overlays]];
CircleOverlay *overlaysmall = [[CircleOverlay alloc] initWithCoordinate:self.location.coordinate radius:100];
[self.mapView addOverlay:overlaysmall];
_targetOverlaySmall = overlaysmall;
CircleOverlay *overlay = [[CircleOverlay alloc] initWithCoordinate:self.location.coordinate radius:self.radius];
[self.mapView addOverlay:overlay];
GeoQueryAnnotation *annotation = [[GeoQueryAnnotation alloc] initWithCoordinate:self.location.coordinate radius:self.radius];
[self.mapView addAnnotation:annotation];
[self updateLocations];
}
}
Related
I am now at a point of teaching myself the use of MapKit in Objective C. I got to the point where I can autozoom to a location that contains several annotations. I represent the annotations with the built in pins. If you click on the pin I have a an alphanumeric 2 character string to represent that spot.
I thought to myself, for better usability, why not replace the pins with the actual data. Kind of like a weathermap where they show the temperature as a pin. Is this doable?
I researched this and all I could find is this:
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *AnnotationViewID = #"annotationViewID";
MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil) {
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID] autorelease];
}
annotationView.image = [UIImage imageNamed:#"location.png"];
annotationView.annotation = annotation;
return annotationView;
}
The problem is that I cannot and should not have to have a custom image for each combination of the two characters. Is there a way for me to draw these numbers at the location of the pin.
I found this reference:
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/LocationAwarenessPG/AnnotatingMaps/AnnotatingMaps.html
Am I on the right track. Are there some full examples I can leverage to better understand the flow.
I want to be able to select that custom pin however and segue or show more details.
Thank you for your time.
Anna, thank you for the link, I tried it and it worked. I made some changes to improve the esthetic of the label and I thought I would post my findings here for reference:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *reuseId = #"MapViewController";
MKAnnotationView *av = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (av == nil)
{
av = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
//UILabel *lbl = [[UILabel alloc] init];;
lbl.backgroundColor = [UIColor clearColor]; // This makes the background clear and just shows the text
lbl.textColor = [UIColor whiteColor]; // Use any colour you wish
lbl.alpha = 1.0; //0.5;
lbl.tag = 42;
lbl.font = [UIFont fontWithName:#"Helvetica-Bold" size:16.0]; // This is optional, I found this fond and size most readable
[av addSubview:lbl];
//Following lets the callout still work if you tap on the label...
av.canShowCallout = YES;
av.frame = lbl.frame;
} else {
av.annotation = annotation;
}
UILabel *lbl = (UILabel *)[av viewWithTag:42];
// I added this to the text to improve its visibility by essentially adding a stroke around the text. Well its a poor man's stroke by adding a shadow
lbl.layer.shadowColor = [[UIColor blackColor] CGColor];
lbl.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
lbl.layer.shadowOpacity = 1.0f;
lbl.layer.shadowRadius = 1.0f;
lbl.text = annotation.title;
return av;
}
I suppose that it's going to be a silly thing but I don't know how to solve it.
First I have to say that my trouble it is because that work sometimes.
I have a main controller which some categories, then touching buttons you can open other view controllers, in this view controllers there are a custom view which contains an mkmapview with annotations.
My problem is that in some categories it deploy the annotations and in the other ones it doesn't.
When it doesn't you can check that the annotations are inside of the MKMapView but it didn't call mapView:ViewForAnnotation until you interact with the map another time.
I will show some code:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
CGRect mapFrame = CGRectMake(0, 0, frame.size.width, frame.size.height);
mapViewDefault = [[MKMapView alloc] initWithFrame:mapFrame];
mapViewDefault.delegate = self;
NSLog(#"Eres delegado!");
CLLocationCoordinate2D initialLocationCoordinate = [DataManager dataManager].centerCoordinate;
[mapViewDefault setCenterCoordinate:initialLocationCoordinate];
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(initialLocationCoordinate, 3000, 3000);
[mapViewDefault setRegion:viewRegion];
[mapViewDefault setUserInteractionEnabled:NO];
[mapViewDefault setScrollEnabled:NO];
[mapViewDefault setZoomEnabled:NO];
if(TAPIsiOS7()){
[mapViewDefault setRotateEnabled:NO];
}
[self addSubview:mapViewDefault];
}
return self;
}
- (void)addListOfPointsWithNumber:(NSArray*)arrayPoints {
NSLog(#"Añadimos anotación al array anotaciones");
[mapViewDefault removeAnnotations:mapViewDefault.annotations];
for (Place *place in arrayPoints) {
if(![place.coordinate isEqualToString:#"0 0"]){
Annotation *annotation = [[Annotation alloc] init];
annotation.coordinate = place.lCoordinate;
annotation.number = place.number;
annotation.place = place;
[mapViewDefault addAnnotation:annotation];
}
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if([annotation isKindOfClass:[Annotation class]]){
NSLog(#"Añadimos anotación al mapa");
Annotation *annotationMap = (Annotation *)annotation;
NSString *identifier = #"Pin";
UIImage *pinImage = [UIImage imageNamed:#"Pin.png"];
MKAnnotationView *pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
pinView.frame = CGRectMake(0, 0, pinImage.size.width, pinImage.size.height);
if (annotationMap.number>0) {
pinImage = [self imageWithView:pinImage andNumber:annotationMap.number];
}
pinView.image = pinImage;
pinView.annotation = annotationMap;
return pinView;
}
}
And 3 images:
I'm pretty sure that this code works great (because I can see that in other categories) and it has to be something with execution times.
If somebody has an idea about what is happening it should be nice.
Thank you all!
You should also be returning something in all cases in your mapView:viewForAnnotation:, whereas you are currently only returning for certain types of annotations. At least return nil and see if that helps -- maybe the warning on this method is preventing some sort of runtime use (though that's a bit of a stretch).
I am drawing a bunch of MKPolygons in my MKMapView. Some of them lay on top of each other. How can I bring a selected polygon to the top/front?
I tried bringSubviewToFront: on a MKPolygonView I create from the polygon layer:
MKPolygonView *view = (MKPolygonView *)[self.mapView viewForOverlay:polygon];
view.strokeColor = [UIColor orangeColor];
[self.mapView bringSubviewToFront:view];
SOLUTION:
I removed
MKPolygonView *view = (MKPolygonView *)[self.mapView viewForOverlay:polygon];
view.strokeColor = [UIColor orangeColor];
[self.mapView bringSubviewToFront:view];
and replaced it with what Craig suggested:
[self.mapView insertOverlay:polygon atIndex:self.mapView.overlays.count];
which then calls the MKMapKit delegate mapView:viewForOverlay: and then I handle the color change there:
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolygon class]] && !((MKPolygon *)overlay).isSelected) {
MKPolygonView* aView = [[MKPolygonView alloc] initWithPolygon:(MKPolygon*)overlay];
aView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
aView.strokeColor = [UIColor yellowColor];
aView.lineWidth = 3;
return aView;
}
else if ([overlay isKindOfClass:[MKPolygon class]] && ((MKPolygon *)overlay).isSelected) {
MKPolygonView* aView = [[MKPolygonView alloc] initWithPolygon:(MKPolygon*)overlay];
aView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
aView.strokeColor = [UIColor orangeColor];
aView.lineWidth = 3;
return aView;
}
}
When you add an overlay to a mapView you can choose where to place it in the list of overlays. Since an overlay can only be in the list once you can move it just by inserting again at the desired location. Since you want it at the top, this should work:
[mapView insertOverlay:overlay atIndex:[mapView.overlays count]];
You should not be calling viewForOverlay. Leave that to iOS. If you need to colour the overlay do it within viewForOverlay because iOS can and will call that when ever it wants and if you return a non-coloured overlay that's what it will draw.
Alright, the problem I'm having is that I have an overlay that is driven by the compass heading for the iphone. Whenever the compass heading changes, the line should move across the map with the heading. There are two overlays, one for the compass and another one. When only the compass overlay is being displayed, the line will flicker as it changes, but when the other line is displayed, the flicker goes away and the line moves smoothly.
- (MKOverlayView *)mapView:(MKMapView *)map viewForOverlay:(id <MKOverlay>)overlay
{
SatFinderAppDelegate *appdel = (SatFinderAppDelegate *)[[UIApplication sharedApplication]delegate];
float s = [appdel.location floatValue];
if (overlay == self.headingline)
{
headinglineView = [[MKPolylineView alloc] initWithPolyline:self.headingline];
headinglineView.fillColor = [UIColor greenColor];
headinglineView.strokeColor = [UIColor greenColor];
headinglineView.lineWidth = 5;
return self.headinglineView;
}
if (overlay == self.routeLine)
{
if (s == 0) {
return routeLineView = nil;
}
routeLineView = [[MKPolylineView alloc] initWithPolyline:self.routeLine];
routeLineView.fillColor = [UIColor cyanColor];
routeLineView.strokeColor = [UIColor cyanColor];
routeLineView.lineWidth = 5;
if (ele < 0) {
routeLineView.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithFloat:12],
[NSNumber numberWithFloat:8],nil];
routeLineView.strokeColor = [UIColor redColor];
}
return routeLineView;
}
return nil;
}
...
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
//line for heading
[self headinglineupdate];
}
....
-(void)headinglineupdate
{
[map removeOverlay:self.headingline];
self.headingline = nil;
self.headingline = [MKPolyline polylineWithCoordinates:locations count:2];
[map addOverlay:headingline];
[headinglineView setNeedsDisplay];
[map setNeedsDisplay];
}
I have a MKMapView with some pins on it. I connect the pins with a MKPolyline view. But the MKPolyline is only shown when I move the map (when the MapView is updated?). I want to see the MKPolyline from the beginning on.
Please inspect the following code:
-(void)plotSnapPosition {
for (id<MKAnnotation> annotation in myMapView.annotations) {
[myMapView removeAnnotation:annotation];
}
for (id<MKOverlay> overlay in myMapView.overlays) {
[myMapView removeOverlay:overlay];
}
NSArray *snaps = self.entry.snapsArray;
CLLocationCoordinate2D *locations = malloc(sizeof(CLLocationCoordinate2D) * snaps.count);
NSInteger counter = 0;
for (Snap *snap in snaps) {
locations[counter] = [snap coordinates];
CLLocationCoordinate2D c = [snap coordinates];
CAHAnnotation *annotation = [[CAHAnnotation alloc] initWithDate:snap.timeAsString coordinate:c counter:counter];
[myMapView addAnnotation:annotation];
counter++;
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:locations count:snaps.count];
MKPolylineView *routeLineView = [[MKPolylineView alloc] initWithPolyline:polyline];
routeLineView.fillColor = [UIColor redColor];
routeLineView.strokeColor = [UIColor redColor];
routeLineView.lineWidth = 5;
[myMapView setVisibleMapRect:polyline.boundingMapRect];
[self.myMapView addOverlay:polyline];
}
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolylineView *routeLineView = [[MKPolylineView alloc] initWithPolyline:overlay];
routeLineView.fillColor = [UIColor blueColor];
routeLineView.strokeColor = [UIColor blueColor];
routeLineView.lineWidth = 3;
return routeLineView;
}
return nil;
}
For testing issues I have set the color of the MKPolyline in the method -(void)plotSnapPosition to red. In the delegate I set it to blue. Only the blue one is shown, after moving the map around.
can someone help me out of this? I think it is only a small mistake. Thank you.
here are the screenshots:
the two pins
after moving the map:
the path after moving the map
Make sure you set the mapView's delegate before adding the overlay. So, in your case
mapView.delegate = self;
[self plotSnapPosition];
Have you tried adding a [overlayView setNeedsDisplay] call when you finish drawing?