MKMapView how to change the User Nearest location pin image? - ios

I want to change user nearest location pin image in map view.
"In my Project i show the some of the shop locations in map view. The locations (lat,long) are get from the api. Here i changed the given location pin image. it works fine. but i need to change the user nearest location pin image in the map view. I already get the distance details from the user current location to given api locations in that which are the locations are below 5 miles that location pin images are need to change. "
Here is my Annotation Code:
// View for Annotation Delegate Code for changing the pin image.
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation: (id<MKAnnotation>)annotation
{
[self.annotationCustom_View removeFromSuperview];
[self.annotationCurrentLoc_View removeFromSuperview];
static NSString *identifier = #"myAnnotation";
CustomMapViewAnnotation * annotationView = (CustomMapViewAnnotation *)[self.locationsMap_View dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annotationView)
{
annotationView = [[CustomMapViewAnnotation alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
if([annotation isKindOfClass:[MKUserLocation class]])
{
annotationView.image = [UIImage imageNamed:#"LocationsYour-Current-Location-Icon"]; // User Current Location Image
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
for(int i=0;i<[locations_ArrayList count];i++)
{
MapViewLocationModel *objValue=[locations_ArrayList objectAtIndex:i];
float value = [objValue.kiosk_distance floatValue];
if(value < 5.0)
{
annotationView.image = [UIImage imageNamed:#"LocationsFridge-Location-Icon"]; // Change the pin image which are the below 5.0 miles distance from the user current locations
}
else
{
annotationView.image = [UIImage imageNamed:#"LocationsBlackDot"]; // given api locations pin images
}
}
});
}
}
annotationView.canShowCallout = NO;
return annotationView;
}
This is my code. any one can help me on this?

Try following:
In order to display the pins in certain map area, first you need to
get the all pins inside the 5 miles.
// 1. Set the map zoom area visible of 5 miles:
mapView.region = MKCoordinateRegionMakeWithDistance(
centerCoordinate,
1609.344f * miles (5 in your case),
1609.344f * miles (5 in your case)
);
// 2. Now get the Rect of this map area:
MKMapRect mRect = self.map.visibleMapRect;
// 3. Get the all pins inside this Rect:
NSSet *annotationSet = [myMapView annotationsInMapRect:mRect];
// print number of annotations
NSLog(#"Number of annotations in rect: %d", annotationSet.count);
// this will return an array from the NSSet
NSArray *annotationArray = [annotationSet allObjects];
// 4. Assign some parameter to this annotation, by taking some property in the annotation class.
// 5. Now in your MapView Delegate method viewForAnnotation check the parameter and do the need full with the respective pins.
Hope this will help you to achieve what you want.

Related

mapkit zoom to maximum scale objective c

I am using mapkit .I have developed simple storyboard application .
1-The mapkit should zoom to maximum scale to show user location on loading mapkit.
2-On clicking loc.png the map should load the description of location with title and subtitle and detail about location
- (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView * annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"testAnnotationView"];
if(annotationView == nil){
annotationView = [[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"testAnnotationView"];
annotationView.image = [UIImage imageNamed:#"loc.png"];
annotationView.canShowCallout = true;
}
return annotationView;
}
How i can accomplish these task?From this link you can download sample project.https://drive.google.com/file/d/0B5pNDpbvZ8SnRExkamtmdkwzeWc/view?usp=sharing
Use this extension of mapKit, and adjust the values as you need, if the values is lower the the zoom is greater
EDITED
OBJECTIVE-C
.h
#import <MapKit/MapKit.h>
#interface MKMapView (Zoom)
-(void)zoomToUserLocation;
-(void)zoomToUserLocationWith:(CLLocationCoordinate2D)coordinate and:(CLLocationDistance)latitudinalMeters and:(CLLocationDistance)longitudinalMeters;
-(void)zoomToUserLocationWith:(CLLocationDistance)latitudinalMeters and:(CLLocationDistance)longitudinalMeters;
#end
.m
#import "MKMapView+Zoom.h"
#implementation MKMapView (Zoom)
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
-(void)zoomToUserLocation
{
[self zoomToUserLocationWith:1000 and:1000];
}
-(void)zoomToUserLocationWith:(CLLocationCoordinate2D)coordinate and:(CLLocationDistance)latitudinalMeters and:(CLLocationDistance)longitudinalMeters
{
[self setRegion:MKCoordinateRegionMakeWithDistance(coordinate, latitudinalMeters, longitudinalMeters)];
}
-(void)zoomToUserLocationWith:(CLLocationDistance)latitudinalMeters and:(CLLocationDistance)longitudinalMeters
{
if(self.userLocation.location != nil){
[self zoomToUserLocationWith:self.userLocation.location.coordinate and:latitudinalMeters and:longitudinalMeters];
}
}
#end
use it
[self.mapView zoomToUserLocation];
or
[self.mapView zoomToUserLocationWith:50 and:50];
or you can use it in
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
[mapView zoomToUserLocationWith:view.annotation.coordinate and:500 and:500];
}
SWIFT
extension MKMapView {
func zoomToUserLocation() {
self.zoomToUserLocation(latitudinalMeters: 1000, longitudinalMeters: 1000)
}
func zoomToUserLocation(latitudinalMeters:CLLocationDistance,longitudinalMeters:CLLocationDistance)
{
guard let coordinate = userLocation.location?.coordinate else { return }
let region = MKCoordinateRegionMakeWithDistance(coordinate, latitudinalMeters, longitudinalMeters)
setRegion(region, animated: true)
}
}
Use it
mapView.zoomToUserLocation()
or
mapView.zoomToUserLocation(latitudinalMeters:50,longitudinalMeters:50)
Hope this helps
Here's code I wrote for zooming an WKInterfaceMap (WatchKit) in and out no less than its minimum (0.0) and no greater than its maximum (the width/height of the world map)—and, that, on an curve that accelerates the zoom increase the farther out you go and decelerates the zoom decrease the closer in you go:
- (void)crownDidRotate:(WKCrownSequencer *)crownSequencer rotationalDelta:(double)rotationalDelta
{
span.latitudeDelta += ((rotationalDelta * rotationalDelta) * (rotationalDelta)) + (span.latitudeDelta * rotationalDelta);
span.longitudeDelta += ((rotationalDelta * rotationalDelta) * (rotationalDelta)) + (span.longitudeDelta * rotationalDelta);
span.latitudeDelta = (span.latitudeDelta < 0) ? 0 : (span.latitudeDelta > MKCoordinateRegionForMapRect(MKMapRectWorld).span.latitudeDelta) ? MKCoordinateRegionForMapRect(MKMapRectWorld).span.latitudeDelta : span.latitudeDelta;
span.longitudeDelta = (span.longitudeDelta < 0) ? 0 : (span.longitudeDelta > MKCoordinateRegionForMapRect(MKMapRectWorld).span.longitudeDelta) ? MKCoordinateRegionForMapRect(MKMapRectWorld).span.longitudeDelta : span.longitudeDelta;
MKCoordinateRegion visibleRegion = MKCoordinateRegionMake(PlanetaryHourDataSource.sharedDataSource.locationManager.location.coordinate, span);
[self.map setRegion:visibleRegion];
}
Not only does this prevent invalid regions (and indicates to the user when the maximum and minimum zoom levels are reached), but it makes sure that the zoom slows down when the map shows more detail, and vice versa:
<iframe src="https://player.vimeo.com/video/313729712" width="640" height="1384" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
The acceleration curve looks like this:
The above answers provide arbitrary values, which will not necessarily correspond to either end of the spectrum.

MKMapView customized pin image lose its accuracy when zoom in/out the map

I have a mapView in my app, and I'm using my own image for the MKAnnotationView, which is the the pin image. Here is my code for setting it.
-(RMAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(RentPin *)annotation{
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[RentPin class]]) {
RMAnnotationView *annotationView = (RMAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(annotationView == nil){
annotationView = [[RMAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = NO;
annotationView.image = [UIImage imageNamed:#"home44.png"];
annotationView.centerOffset = CGPointMake(-10, -10);
}else{
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
It is working fine and the customized image is also showing properly, but when I pinch the mapView for zooming in/out the map, I noticed that the customized image loses its accuracy on the map. Please have a look the images following.
https://www.dropbox.com/s/irrgmohppf08fzr/image1.png
This image shows the pin is at this position, which is quite accurate.
https://www.dropbox.com/s/vvlr4ckk6molqd7/image2.png
After I zoomed out the mapView, the pin crossed the street and showing that this address is in the lake....
(Sorry for the links, since I can't post images because of insufficient reputation.)
Anyone could help me regarding this? my pin image is 44x44 and I also tried setting centerOffset of the pin, it cannot dynamically solved this problem in all the zoom levels.
It's simply the wrong center offset. But be aware that the center offset depends on the type of annotation view you are using. I don't know what RMAnnotationView is. If it's a subclass of MKAnnotationView, the centerOffset should be CGPointMake(0, -imageHeight / 2).

Google maps for iOS [map balloons]

How do I make map balloons when a marker is being touched or tapped in iOS?
to put it simply i want my application's map feature to be able to popup a map balloon to display certain information on the location where the marker is located.
I'm using google maps since i've heard that for now it is more accurate than the Mapkit in iOS.
the image below is my objective in this question:
If you want this custom map balloons for your markers, while using google maps sdk for ios, you can use the function
- (UIView *) mapView: (GMSMapView *) mapView markerInfoWindow: (GMSMarker *) marker
This allows you to display a custom info window for a marker instead of the default infowindow. You need to design a view as shown in your picture , assign the required values and return the view in this function. Please check this earlier post to see an example of making a custom infowindow . You can adjust how the infowindow is located with respect to the marker, by setting value for the property marker.infoWindowAnchor
To create a balloon like annotation , you need to override MKMapView's method
- (MKAnnotationView *)viewForAnnotation:(id < MKAnnotation >)annotation
Like this:
- (MKAnnotationView *)viewForAnnotation:(id < MKAnnotation >)annotation{
static NSString* annotationIdentifier = #"Identifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if(annotationView)
return annotationView;
else
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
// here we say NO to call out, it means the default popover type view wont open when you click on an //annotation and you can override to show your custom popover
annotationView.canShowCallout = NO;
// here you need to give a ballon image
annotationView.image = [UIImage imageNamed:[NSString stringWithFormat:#"balloon.png"]];
return annotationView;
}
return nil;
}
To create the custom popover/ view that opens when you tap on an annotation , you need to override MKMapViewDelegate's method
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
Here in this method you woould need to create a Popover Controller and present it.

MKAnnotation not updating position

I am using the HGMovingAnnotation and HGMovingAnnotationView code off of github to animate a MKAnnotation on an MKmap. When I run the example project from HG project everything works fine.
I have altred the original HG project to allow me to manually push a new coordinate to the HGMapPath and then move the annotation where I want it.
I have placed a button, for testing, to run the manual process and everything works fine. The annotation moves around the screen. The issue is, when I try to now call this manual method with data from a live socket.io connection, the map annotation won't move.
Also, when the map first loads the annotation won't show up until I move the map a little bit. The same thing for the moving annotation manually, it won't show the movement from the stream of data, until I zoom the map. But if I do the push button way, avoiding the io stream, the annotation moves without needing to zoom or pan the map?
PLACING THE VIEW ANNOTATIONS
if(doubleLat && doubleLng) {
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(doubleLat, doubleLng);
//Create path object
self.assignedAmbPath = [[HGMapPath alloc] initWithCoordinate:coordinate];
HGMovingAnnotation *movingObject = [[HGMovingAnnotation alloc] initWithMapPath:self.assignedAmbPath];
self.movingAssignedAmbObject = movingObject;
// add the annotation to the map
[self.mapView addAnnotation:movingObject];
// zoom the map around the moving object
MKCoordinateSpan span = MKCoordinateSpanMake(0.01, 0.01);
MKCoordinateRegion region = MKCoordinateRegionMake(MKCoordinateForMapPoint(self.movingAssignedAmbObject.currentLocation), span);
[self.mapView setRegion:region animated:YES];
// start moving the object
[movingObject start];
}
CODE THAT WORKS
- (IBAction)testMoveBtnPressed:(id)sender {
//TODO: move x and y
DLog(#"============== Test move button was pressed ================ ");
NSLog(#"");
int randn = (random() % 15)+15;
float pscale = (float)randn / 10000;
double lat = 39.9813855 + pscale;
double lng = -75.1502155 + pscale;
for (id<MKAnnotation> annotation in self.mapView.annotations){
MKAnnotationView* anView = [self.mapView viewForAnnotation: annotation];
if (![annotation isKindOfClass:[PhoneAnnotation class]]){
// Process annotation view
[((HGMovingAnnotation *)annotation) trackToNewPosition:CLLocationCoordinate2DMake(lat, lng)];
}
}
}
CODE THAT DOESN'T WORK
{
//TODO: move thing to new location
double doubleLat = [lat doubleValue];
double doubleLng = [lng doubleValue];
// NSLog(#"--------------- Jason it is ------------- Latitude being passed in is %f", doubleLat);
// NSLog(#"--------------- Jason it is ------------- Longitude being passed in is %f", doubleLng);
//
// [self.movingAssignedAmbObject trackToNewPosition:CLLocationCoordinate2DMake(doubleLat, doubleLng)];
for (id<MKAnnotation> annotation in self.mapView.annotations){
MKAnnotationView* anView = [self.mapView viewForAnnotation: annotation];
if (![annotation isKindOfClass:[PhoneAnnotation class]]){
// Process annotation view
[((HGMovingAnnotation *)annotation) trackToNewPosition:CLLocationCoordinate2DMake(doubleLat, doubleLng)];
}
}
}
The issue is the HG library though works as described doesn't work proper, unless your using the path, if you don't create the annotation with a coordinate attached, which it doesn't.

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.

Resources