MapBox: How to remove a shape and draw another shape? - ios

I created annotation for shape
_path = [RMAnnotation annotationWithMapView:_mapView
coordinate: _userLocation.coordinate
andTitle:#"Path"];
[_mapView addAnnotation:_path];
in delegate I wrote
- (RMMapLayer *)mapView:(RMMapView *)mapView layerForAnnotation:(RMAnnotation *)annotation
{
if ([annotation.title isEqualToString:#"Path"])
{
_lineBetweenTwoBeacon = [[RMShape alloc] initWithView:mapView];
_lineBetweenTwoBeacon.lineColor = [UIColor redColor];
_lineBetweenTwoBeacon.lineWidth = 10.0f;
return _lineBetweenTwoBeacon;
}
else
{
marker = [[RMMarker alloc] initWithUIImage:[UIImage imageNamed:#"userPin"]];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 80, 80)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
marker.leftCalloutAccessoryView = imageView;
return marker;
}
}
Next step I draw shape
[_lineBetweenTwoBeacon addQuadCurveToCoordinate:firstBeaconCoord controlCoordinate:secondBeaconCoord];
But how to remove all shapes from the map and add new shape.
Now the shape lay to the shape, it's not correct.
Will be better if _lineBetweenTwoBeacon redraw every time.
Thank you, for help!

When you manually create an RMShape, you need to tell it where to move and to draw after creating it with methods like -moveToCoordinate: and -addLineToCoordinate:. If you just have basic needs, I would recommend trying RMPolylineAnnotation, which handles the drawing for you.

Related

how to display marker title for multiple markers without tapping on it in iOS swift like places in photo gallery in iOS

Im able to display info window of markers but can we display the info when the map loads without even tapping on marker?
Okay, since google maps currently don't provide this functionality by default here is a work around. When you create your marker manipulate it as follows:
First you create a view and add your label and image to it.
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 20)];
// Set label properties as required including marker Name
UIImageView *markerIconImageView = [[UIImageView alloc]initWithFrame:CGRectMake(35, 10, 30, 50)];
// Set image properties as required including image which will be displayed as marker
UIView *markerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
[markerView addSubview:label];
[markerView addSubview:markerIconImageView];
Then you create a marker and assign it the image of above view:
GMSMarker *marker = [[GMSMarker alloc] init];
marker.icon = [self imageWithView:markerView];
marker.position = coordinates for marker;
marker.appearAnimation = kGMSMarkerAnimationPop;
marker.map = your map;
For reference here is my function for converting view to image:
-(UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContext(view.bounds.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
We have converted the view to image because. It takes up lesser space in memory.
Hope this helps. And gives you an idea for the approach.

Marker icon image duplication

I have two images: small for default marker state and big for selected.
After tapping on marker, I'm changing marker icons for new state, but sometimes I see that small icon is placed over big icon. I thought it should be updated with tracksViewChanges property, but it doesn't.
You can see green marker on image, which have big icon under small.
My code is simple:
-(BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker
{
if (self.lastMarker) {
Car *lastCar = (Car*)self.lastMarker.userData;
self.lastMarker.icon = [lastCar.provider smallPinIcon];
}
Car *car = (Car*)marker.userData;
marker.tracksViewChanges = YES;
marker.icon = [car.provider bigPinIcon];
[UIView animateWithDuration:0.01 animations:^{
}
completion:^(BOOL finished) {
marker.tracksViewChanges = NO;
}];
self.lastMarker = marker;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] init];
bounds = [bounds includingCoordinate:self.userMarker.position];
bounds = [bounds includingCoordinate:marker.position];
GMSCameraUpdate *update = [GMSCameraUpdate fitBounds:bounds withEdgeInsets:UIEdgeInsetsMake(120, 60, 120, 60)];
[self.mapView animateWithCameraUpdate:update];
return YES;
}
Methods smallPinIcon and bigPinIcon caching actual images.
This is Google Maps SDK bug or I'm doing something wrong?

Rotate Annotation Custom Image [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am clearly not getting this. I'm trying to work out how to rotate a custom image of map annotations. i.e. multiple icons pointing different directions. I have loop'ed over a whole bunch of airplane data and I want to simply show the direction the plane is heading.
Review the code that I have managed to piece together to get at least half of it working and provide a suggestive idea on how to turn the image based on a variable.
Abstract View of the loop'ed data
NSMutableArray *locations = [[NSMutableArray alloc]init];
CLLocationCoordinate2D location;
MKPointAnnotation *myAnn;
myAnn = [[MKPointAnnotation alloc]init];
location.latitude = nLatitudeFloat;
location.longitude = nLongitudeFloat;
myAnn.coordinate = location;
myAnn.title = nRealname;
//Add the Annotation object to the list so when the map is presented all points are listed on the map.
[locations addObject:myAnn];
//[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
[self.mapView addAnnotations:locations];
Update of the annotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]]) return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
// Try to dequeue an existing pin view first.
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"airplane21.png"] ;
pinView.calloutOffset = CGPointMake(0, 32);
pinView.transform = CGAffineTransformMakeRotation(30); <------AT THE MOMENT I HAVE JUST HARD CODED THIS TO SEE IF IT WORKS. IT ROTATES THE ENTIRE ANNOTATION
// Add a detail disclosure button to the callout.
//UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
//pinView.rightCalloutAccessoryView = rightButton;
// Add an image to the left callout.
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"airplane21.png"]];
pinView.leftCalloutAccessoryView = iconView;
iconView.transform = CGAffineTransformMakeRotation(30);
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Any ideas?
I have seen this by the way. I just wasn't confident to know if it would be suitable or not.
Rotate annotation image on MKMapView
I had the same problem and I have a solution that seems to work.
You need to first make a custom annotation that can hold the data that you want (ex. coordinates, your plane heading). When you loop through your data make sure you're using that custom annotation. For example
CustomAnnotation* annotation = [[CustomAnnotation alloc] init];
annotation.coordinates = ...
annotation.bearing = ...
Then in your viewForAnnotation method, you can get that info by doing something like
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
CustomAnnotation* myAnn = (CustomAnnotation*)annotation;
double bearing = myAnn.bearing; // or whatever it's called
...
}
Hope this helped.
Edit: For rotating your image, I found the following code snippet somewhere. It works but it pixellates your image a little bit.
#interface UIImage (RotationMethods)
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees;
#end
#implementation UIImage (RotationMethods)
static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees
{
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create the bitmap context
//UIGraphicsBeginImageContext(rotatedSize); // For iOS < 4.0
UIGraphicsBeginImageContextWithOptions(rotatedSize, NO, 0.0);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
// Move the origin to the middle of the image so we will rotate and scale around the center.
CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
// Rotate the image context
CGContextRotateCTM(bitmap, DegreesToRadians(degrees));
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
#end
Stick that in your .m, and on any UIImage you can now do [someUIImage imageRotatedByDegrees:yourDegrees];
So now in your viewForAnnotation method you can do something like
UIImage* image = [[UIImage imageNamed:#"yourImage.png"] imageRotatedByDegrees:degrees];
annView.image = image;

multiple punch-out style mask?

I've done simple CALayer masks before but I think I'm getting confused on what they do. I'm trying to have a punch out effect with several (2) views.
Here's what I have so far. I'm looking to have a white square with punched out label and image (so you can see the brown background through it. Where am I going wrong?
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor brownColor];
self.viewToPunch = [[UIView alloc] initWithFrame:CGRectZero];
[self.view addSubview:self.viewToPunch];
self.viewToPunch.backgroundColor = [UIColor whiteColor];
self.punchLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.punchLabel.textColor = [UIColor blackColor];
self.punchLabel.font = [UIFont boldSystemFontOfSize:20.0];
self.punchLabel.text = #"punch";
self.punchLabel.textAlignment = NSTextAlignmentCenter;
self.punchImage = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:#"plus"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
[self.punchImage setContentMode:UIViewContentModeCenter];
self.viewsToPunch = #[self.punchLabel,self.punchImage];
[self punch:self.viewToPunch withUIViews:self.viewsToPunch];
}
- (void)punch:(UIView *) viewToPunch withUIViews:(NSArray *)viewsToPunch
{
CALayer *punchMask = [CALayer layer];
punchMask.frame = viewToPunch.frame;
NSMutableArray *sublayers = [[NSMutableArray alloc] init];
for (UIView *views in viewsToPunch){
[sublayers addObject:views.layer];
}
punchMask.sublayers = sublayers;
punchMask.masksToBounds = YES;
viewToPunch.layer.mask = punchMask;
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.viewToPunch.frame = CGRectMake(50, 50, 100, 100);
self.punchLabel.frame = CGRectMake(0, 0, 100, 100);
self.punchImage.frame = CGRectMake(0, 0, self.viewToPunch.frame.size.width, 40.);
[self punch:self.viewToPunch withUIViews:self.viewsToPunch];
}
So not only do the frames seem to be off, it seems to be the opposite of a punch out. How do I invert the mask and fix up the frames?
Thanks a lot for any help! I put it in a method punch:withUIViews: so I can hopefully reuse it in other areas.
When you apply a mask to a CALayer, it only gets drawn in the parts where the mask is not transparent. But you're simply applying an empty (transparent) mask, with the wrong coordinates (which is why your view isn't completely transparent: the mask isn't covering the view completely; it should be punchMask.frame = viewToPunch.bounds;)
You might want to look into CAShapeLayer and assign it a path. Use that as mask layer.
For example, see CAShapeLayer mask view or Getting Creative with CALayer Masks (cached blog post).
I tried to combine mask of CAGradationLayer and CAShapeLayer, and It is possible.
https://stackoverflow.com/a/32220792/3276863

Route-Me: Alpstein fork - Customize cluster icon and display cluster count

I am using Route-Me: Alpstein fork for developing an iOS app. The original Route-Me/Mapbox code had an option to customize the cluster icon and also the the cluster count. I've been looking for a way to do this with the Route-Me: Alpstein fork.
Something similar to this:
- (RMMapLayer *)mapView:(RMMapView *)mapView layerForAnnotation:(RMAnnotation *)annotation
{
if (annotation.isUserLocationAnnotation)
return nil;
RMMapLayer *layer = nil;
if (annotation.isClusterAnnotation)
{
layer = [[RMMarker alloc] initWithUIImage:[UIImage imageNamed:#"circle.png"]];
layer.opacity = 0.75;
layer.bounds = CGRectMake(0, 0, 75, 75);
[(RMMarker *)layer setTextForegroundColor:[UIColor whiteColor]];
[(RMMarker *)layer changeLabelUsingText:[NSString stringWithFormat:#"%i", [annotation.clusteredAnnotations count]]];
}
else
{
layer = [[RMMarker alloc] initWithMapboxMarkerImage];
}
return layer;
}
I cannot see 'isClusterAnnotation' defined anywhere in the source. How can I achieve the same results using the Route-Me: Alpstein fork? Any help would be greatly appreciated.
In my project I used the following, inside the mapView:layerForAnnotation: method of the map delegate:
if ([annotation.annotationType isEqualToString:#"RMClusterAnnotation"]) {
UIImage *clusterImage = [UIImage imageNamed:#"foo.png"];
RMMarker *newMarker = [[RMMarker alloc] initWithUIImage:clusterImage];
// this is how I managed to count the annotations inside a cluster
NSInteger annotationsInCluster = [((RMQuadTreeNode *)annotation.userInfo).annotations count];
// you can add a label to the annotation with the number of clustered annotations
[newMarker changeLabelUsingText: [NSString stringWithFormat:#"%i", annotationsInCluster]];
return newMarker;
}
Hope this works for you!

Resources