iOS Mapbox Custom Marker Will Not Appear - ios

Custom Marker Image will not appear only default marker appears in it's place.
In ViewWillAppear:
RMPointAnnotation *annotation3 = [[RMPointAnnotation alloc] initWithMapView:parkMap coordinate:coordinate andTitle:title];
[parkMap addAnnotation:annotation3];
- (RMMapLayer *)mapView:(RMMapView *)mapView layerForAnnotation:(RMAnnotation *)annotation
{
if (annotation.isUserLocationAnnotation)
return nil;
RMMarker *marker;
marker = [[RMMarker alloc] initWithUIImage:[UIImage imageNamed:#"square_small.png"]];
marker.canShowCallout = YES;
return marker;
}

Check the docs and don't use RMPointAnnotation.
If you wish to customize the layer appearance in more detail, you should instead create an RMAnnotation and configure its layer directly. Providing a layer manually for instances of RMPointAnnotation will not have any effect.
https://github.com/mapbox/mapbox-ios-sdk/blob/509fa7df46ebd654d130ab2f530a8e380bf2bd59/MapView/Map/RMPointAnnotation.h#L33

Related

MKMapView with custom pins return to red standard pins on reload

I have an MKMapView that I add pins to. They load correctly with their relevant graphics but if I zoom in and zoom back out they loose their graphic and turn into a standard red pin with the only customisation being the pin name (even my disclosure indicator disappear).
So far to try and fix it I've tried:
Tried png’s, checked on faster device, Changed everything from MKPinAnnotation to MKAnnotation, returning to a normal MKAnnotation instead of my custom CBAnnotation, Various sample codes for loading custom pins, Lowered quality of map overlay in case it was a loading issue but still an issue.
- (void)addPins {
mapPinsArray = [[NSMutableArray alloc] init];
for (MapPoint *mappoint in mapPointsArray) {
CBAnnotation *annotation = [[CBAnnotation alloc] init];
annotation.coordinate = CLLocationCoordinate2DMake(mappoint.loclat, mappoint.loclong);
annotation.title = mappoint.stopAreaName;
annotation.mapPoint = mappoint;
[mapPinsArray addObject:annotation];
[self.myMapView addAnnotation:annotation];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(CBAnnotation *)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
//do nothing
return nil;
} else {
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"trailPoint"];
annotationView.canShowCallout = YES;
ButtonWithData *accessoryViewButton = [[ButtonWithData alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
[accessoryViewButton setBackgroundImage:[UIImage imageNamed:#"right_arrow"] forState:UIControlStateNormal];
accessoryViewButton.buttonData = annotation.mapPoint;
[accessoryViewButton addTarget:self action:#selector(disclosureButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
annotationView.rightCalloutAccessoryView = accessoryViewButton;
if (![[NSUserDefaults standardUserDefaults] boolForKey:annotation.mapPoint.stopAnimalName]) {
annotationView.image = [annotation.mapPoint lockedPinImage];
} else {
annotationView.image = [annotation.mapPoint unlockedPinImage];
}
return annotationView;
}
}
Fixed my own problem. I subclassed MKMapView to GenericMapView so that my code was cleaner (removing showsUserLocation, zoom/scroll/rotateEnabled, showsCompass etc. from the actual View Controller) but this meant the delegate wasn't setting correctly and viewForAnnotation wasn't being called on the pins reload.

How to make custom UIView OR label on GMSMarker Google

I have to add a custom label on Marker pin of Google maps in IOS.
I have already implemented markerInfoWindow method. But it works after i tapped on marker/Pin.
I need to show custom label at start as long as mapview will load on view without performing any action. As we can set icon or title on the marker, I need to show my own Custom view on it.
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker {
CLLocationCoordinate2D anchor = marker.position;
// CGPoint point = [mapView.projection pointForCoordinate:anchor];
// self.calloutView.title = marker.title;
[self.calloutView setFrame:CGRectMake(0, 50, 25, 25)];
self.calloutView.layer.cornerRadius = 11.0;
self.calloutView.layer.masksToBounds = YES;
self.calloutView.layer.borderColor = [UIColor clearColor].CGColor;
self.calloutView.layer.borderWidth = 0.0;
self.calloutView.hidden = NO;
return self.calloutView;
}
Use this code to add an image for GMSMarker:
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = MARKER_POSITION;
marker.infoWindowAnchor = CGPointMake(0.44f, 0.45f);
marker.icon = [UIImage imageNamed:#"CustomMarkerImageName"];
You can also use this delegate method to provide custom view for additional info:
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker {
InfoWindow *view = [[[NSBundle mainBundle] loadNibNamed:#"InfoWindow" owner:self options:nil] objectAtIndex:0];
view.name.text = #"Place Name";
view.description.text = #"Place description";
view.phone.text = #"123 456 789";
view.placeImage.image = [UIImage imageNamed:#"customPlaceImage"];
view.placeImage.transform = CGAffineTransformMakeRotation(-.08);
return view;
}
Check this answer as a reference: https://stackoverflow.com/a/16767124/2082569
If I understand correctly, the ask is to show the info window for a particular marker programmatically.
[self.mapView setSelectedMarker:marker];
To achieve camera refocus similar to if a user had tapped the marker, do something like:
GMSCameraPosition *cameraPosition =
[[GMSCameraPosition alloc] initWithTarget:marker.position
zoom:15
bearing:0
viewingAngle:0];
[self.mapView animateToCameraPosition:cameraPosition];

MKAnnotationView Subviews

Currently, I am having an issue with my project in implementing a custom MKAnnotationView that has multiple custom UIImageViews. So these custom UIImageViews have a clear button on top of them to not have to add gesture recognizers.
As you can see, it would be beneficial to actually tap the MKAnnotationView subviews and have some action happen.
I implemented a protocol for the MKAnnotationView where each image subview within the MKAnnotationView makes a callback to the controller that is the owner of the MKMapView... Heres the code...
PHProfileImageView *image = [[PHProfileImageView alloc] initWithFrame:CGRectMake(newX - radius / 5.0f, newY - radius / 5.0f, width, height)];
[image setFile:[object objectForKey:kPHEventPictureKey]];
[image.layer setCornerRadius:image.frame.size.height/2];
[image.layer setBorderColor:[[UIColor whiteColor] CGColor]];
[image.layer setBorderWidth:2.0f];
[image.layer setMasksToBounds:YES];
[image.profileButton setTag:i];
[image.profileButton addTarget:self action:#selector(didTapEvent:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:image];
- (void)didTapEvent:(UIButton *)button
{
NSLog(#"%#", [self.pins objectAtIndex:button.tag]);
if (self.delegate && [self.delegate respondsToSelector:#selector(didTapEvent:)]) {
[self.delegate JSClusterAnnotationView:self didTapEvent:[self.pins objectAtIndex:button.tag]];
}
}
So as you can see, I already attempt to log the result of the tapped image but nothing :(. Is the way I'm implementing this not the way to go? Am I supposed to have CAShapeLayers or something? Not really sure at this point. Anyone got any ideas?
Edit
Im thinking that I might have to implement a custom callout view. Since a callout view actually adds buttons to its view and can respond to touch events... Not totally sure though because callouts are only shown once the annotation view is tapped. And in this case, the ACTUAL annotation view is the middle label
So I resized the mkannotationview's frame to a much larger frame and apparently all the subviews are actually not within the MKAnnotationView's bounds, so the subviews aren't actually being tapped. Now that Im thinking about this solution, it probably wasn't the best solution.
If anyone has any suggestions rather than adding subviews to a MKAnnotationView to create the view I currently have, that would be great!
For the Custom AnnotationView with Clickable Buttons, you have to create custom AnnotationView SubClass in the Project. For that create a new file.
And add these two methods to the implementation file.
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
UIView* hitView = [super hitTest:point withEvent:event];
if (hitView != nil)
{
[self.superview bringSubviewToFront:self];
}
return hitView;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
CGRect rect = self.bounds;
BOOL isInside = CGRectContainsPoint(rect, point);
if(!isInside)
{
for (UIView *view in self.subviews)
{
isInside = CGRectContainsPoint(view.frame, point);
if(isInside)
break;
}
}
return isInside;
}
Then go to the ViewController.m file again and modify the viewDidLoad method as this.
- (void)viewDidLoad {
[super viewDidLoad];
self.mapKit.delegate = self;
//Set Default location to zoom
CLLocationCoordinate2D noLocation = CLLocationCoordinate2DMake(51.900708, -2.083160); //Create the CLLocation from user cordinates
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 50000, 50000); //Set zooming level
MKCoordinateRegion adjustedRegion = [self.mapKit regionThatFits:viewRegion]; //add location to map
[self.mapKit setRegion:adjustedRegion animated:YES]; // create animation zooming
// Place Annotation Point
MKPointAnnotation *annotation1 = [[MKPointAnnotation alloc] init]; //Setting Sample location Annotation
[annotation1 setCoordinate:CLLocationCoordinate2DMake(51.900708, -2.083160)]; //Add cordinates
[self.mapKit addAnnotation:annotation1];
}
Now add that custom View to the ViewController.xib.
Now create this delegate method as below.
#pragma mark : MKMapKit Delegate
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
AnnotationView *pinView = nil; //create MKAnnotationView Property
static NSString *defaultPinID = #"com.invasivecode.pin"; //Get the ID to change the pin
pinView = (AnnotationView *)[self.mapKit dequeueReusableAnnotationViewWithIdentifier:defaultPinID]; //Setting custom MKAnnotationView to the ID
if ( pinView == nil )
pinView = [[AnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID]; // init pinView with ID
[pinView addSubview:self.customView];
addSubview:self.customView.center = CGPointMake(self.customView.bounds.size.width*0.1f, -self.customView.bounds.size.height*0.5f);
pinView.image = [UIImage imageNamed:#"Pin"]; //Set the image to pinView
return pinView;
}
I also got this answer few months ago from someone posted on Stackoverflow. I modified it to my project as I want. Hope this will do your work.

Trying to change MKPointAnnotation colour but losing the title

I am trying to change my pin colour to purple, when I do it I lose the title though. Code is:
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationController.navigationBarHidden=YES;
//init the location manager
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager requestWhenInUseAuthorization];
self.mapView.showsUserLocation=YES;
self.userGeoPoint=self.message[#"userLocation"];
self.pinView = [[MKPointAnnotation alloc] init];
self.pinView.title=self.message[#"fromUser"];
self.coord = CLLocationCoordinate2DMake(self.userGeoPoint.latitude, self.userGeoPoint.longitude);
self.pinView.coordinate=self.coord;
//use a slight delay for more dramtic zooming
[self performSelector:#selector(addPin) withObject:nil afterDelay:0.5];
}
-(void)addPin{
[self.mapView addAnnotation:self.pinView];
[self.mapView selectAnnotation:self.pinView animated:YES];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.coord, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotationPoint
{
if ([annotationPoint isKindOfClass:[MKUserLocation class]])//keep the user as default
return nil;
static NSString *annotationIdentifier = #"annotationIdentifier";
MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc]initWithAnnotation:annotationPoint reuseIdentifier:annotationIdentifier];
pinView.pinColor = MKPinAnnotationColorPurple;
//now we can throw an image in there
return pinView;
}
I tried setting the title property for MKPinAnnotation but there isn't one. Is there anyway I can get around this?
In viewForAnnotation, you need to set canShowCallout to YES (it's NO by default):
pinView.pinColor = MKPinAnnotationColorPurple;
pinView.canShowCallout = YES;
A couple of unrelated points:
It looks like you have a property named pinView of type MKPointAnnotation that you are using to create the annotation object in viewDidLoad. Then in viewForAnnotation, you have a local variable also named pinView of type MKPinAnnotationView. Although there is no naming conflict here, it causes and implies some conceptual confusion. MKPointAnnotation is an annotation model class while MKPinAnnotationView is an annotation view class -- they are completely different things. It would be better to name the annotation property pin or userAnnotation for example.
This comment in viewForAnnotation:
//now we can throw an image in there
seems to imply that you could set a custom image in the view at this point. Setting a custom image in a MKPinAnnotationView is not recommended since that class is designed to display default pin images in one of three colors. To use a custom image, create a plain MKAnnotationView instead.
The pinColor property was deprecated in iOS 9. From iOS 9 onwards you should use pinTintColor which takes a UIColor rather than a MKPinAnnotationColor.
Old:
MKPinAnnotationView *view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
view.pinColor = MKPinAnnotationColorPurple;
New:
MKPinAnnotationView *view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
view.pinTintColor = [UI Color purpleColor];
There is more information available in the Apple docs.
I just upgrade to ios 10, apple changed the api.
pinColor no longer in use, instead, use tintColor
New:
MKPinAnnotationView *view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
view.tintColor = [UIColor purpleColor];
Note that the pin title will be displayed when the user taps it:
If the value of this property is true, a standard callout bubble is shown when the user taps a selected annotation view. The callout uses the title and subtitle text from the associated annotation object.
(  https://developer.apple.com/documentation/mapkit/mkannotationview/1452451-canshowcallout )

Resizing MKCircle on MKMapView is flickering

I'm trying to solve a problem since few days and I've got no good results. I've got a point and a circle on MKMapView. I've got UISlider and want to change size of MKCircle. Size is changed but during resizing this circle flickers and blinks.
Here is my code:
#implementation ViewController {
Annotation *_annotation;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_annotation = [[Annotation alloc] init];
[_annotation setCoordinate: CLLocationCoordinate2DMake(0, 0)];
[self.mapView addAnnotation:_annotation];
[self.mapView setCenterCoordinate:_annotation.coordinate animated:YES];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(_annotation.coordinate, 1000, 1000);
[self.mapView setRegion:region];
[self _addCircleOnCurrentLocationWithRadius:_slider.value];
}
- (IBAction)onSliderChanged:(UISlider *)sender {
[self.mapView removeOverlays:self.mapView.overlays];
[self _addCircleOnCurrentLocationWithRadius:sender.value];
}
- (void)_addCircleOnCurrentLocationWithRadius:(CGFloat)radius {
MKCircle *circle = [MKCircle circleWithCenterCoordinate:_annotation.coordinate radius:radius];
[self.mapView addOverlay:circle level:MKOverlayLevelAboveRoads];
}
#pragma mark - MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
MKPinAnnotationView *view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"Annotation"];
return view;
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay {
MKCircleView *view = [[MKCircleView alloc] initWithCircle:overlay];
view.fillColor = [UIColor redColor];
view.strokeColor = [UIColor blueColor];
view.alpha = 0.3;
return view;
}
#end
I've tried:
removing old overlays and adding new one,
doing as above with NSOperationQueue
Here is a screen recording how it looks like.
I see that is possible to do, Apple did this in Reminders app.
Also I'm familiar with following topics:
Smooth resizing of MKCircle
Moving MKCircle on MKMapview and dragging MKMapview
Smooth resizing of MKCircle
Thank you in advance.
Edit
I've did it. I will add an answer with class which supports resizing today or tomorrow.
I've did it by creating subclass of MKCircleView and override - (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)ctx method. TSCircleView class is shared on github here..

Resources