Hello Everyone i am new in developing app for I-Phone I have stuck in the Custom ANNotationView in mapKit. When i load map first Time it shows correctly Custom View , But after scrolling map it become the red colored PIN (default annotation in MapKit). Kindly Help me . Thank You in advance.
I am using the following code in viewForAnnotation delegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation: (id<MKAnnotation>)annotation
{
UIImageView *AvatarView=[[UIImageView alloc]initWithFrame:CGRectMake(0,0, 30, 30)];
AvatarView.layer.cornerRadius =AvatarView.frame.size.width / 2;
AvatarView.layer.masksToBounds = YES;
AvatarView.layer.borderColor =(__bridge CGColorRef)([UIColor colorWithRed:34.0/255.0 green:28.0/255.0 blue:36.0/255.0 alpha:1.0]) ;
AvatarView.layer.borderWidth = 1.0;
AvatarView.layer.zPosition=1;
MKPinAnnotationView* pinView =
(MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
// Try to dequeue an existing pin view first.
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"CustomPinAnnotationView"];
// If an existing pin view was not available, create one.
//pinView.animatesDrop = YES;
annotationView.canShowCallout = YES;
if([[responseDataArray objectAtIndex:k] valueForKey:#"thumbPath"]!=nil && [[[responseDataArray objectAtIndex:k] valueForKey:#"thumbPath"] length]>0)
{
NSString *imgPath =[NSString stringWithFormat:#"%#%#",WebSiteUrl,[[responseDataArray objectAtIndex:k] valueForKey:#"thumbPath"]];
k++;
NSString* webStringURL = [imgPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL* url = [NSURL URLWithString:webStringURL];
NSString *imageName = [placeholderImageArray objectAtIndex:(arc4random() %placeholderImageArray.count)];
[AvatarView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:imageName]];
}
[annotationView addSubview:AvatarView];
return annotationView;
}
else
{
k=0;
pinView.annotation = annotation;
}
return pinView;
}
I am using the following code to add Annotation
MKPointAnnotation *myAnnotation = [[MKPointAnnotation alloc] init];
myAnnotation.coordinate = coord;
myAnnotation.title = titleStr;
myAnnotation.subtitle = #"Best bar in Town";
[myLocation addAnnotation:myAnnotation];
It never goes to else part. I don't know what is the problem. Please help me to solve out this problem. A big thanks to You.
Related
I'm creating a Mac OSX application with Cordova-osx. I've tried to implement all solutions I've seen about having rounded corners for my app but none of them work. Last resource will be removing the shadow and creating the corners with CSS but I don't really like that approach.
So, this is the file in charge of creating the webview and loading it. And this was my approach:
- (void) awakeFromNib
{
_commandDelegate = [[CDVCommandDelegateImpl alloc] initWithViewController:self];
self.webViewDelegate.viewController = self;
NSURL* appURL = nil;
NSString* loadErr = nil;
if ([self.startPage rangeOfString:#"://"].location != NSNotFound) {
appURL = [NSURL URLWithString:self.startPage];
} else if ([self.wwwFolderName rangeOfString:#"://"].location != NSNotFound) {
appURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#/%#", self.wwwFolderName, self.startPage]];
} else {
NSString* startFilePath = [self.commandDelegate pathForResource:self.startPage];
if (startFilePath == nil) {
loadErr = [NSString stringWithFormat:#"ERROR: Start Page at '%#/%#' was not found.", self.wwwFolderName, self.startPage];
NSLog(#"%#", loadErr);
self.loadFromString = YES;
appURL = nil;
} else {
appURL = [NSURL fileURLWithPath:startFilePath];
}
}
if (!loadErr) {
NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
self.webView.layer.cornerRadius = 10;
self.webView.layer.opaque = NO;
[[self.webView mainFrame] loadRequest:appReq];
} else {
NSString* html = [NSString stringWithFormat:#"<html><body> %# </body></html>", loadErr];
[[self.webView mainFrame] loadHTMLString:html baseURL:nil];
}
for (NSString* pluginName in self.startupPluginNames) {
[self getCommandInstance:pluginName];
}
// initialize items based on settings
BOOL enableWebGL = [[self.settings objectForKey:#"EnableWebGL"] boolValue];
WebPreferences* prefs = [self.webView preferences];
// Note that this preference may not be Mac App Store safe
if (enableWebGL && [prefs respondsToSelector:#selector(setWebGLEnabled:)]) {
[prefs performSelector:#selector(setWebGLEnabled:) withObject:[NSNumber numberWithBool:enableWebGL]];
}
}
Which basically is adding this:
self.webView.layer.cornerRadius = 10;
self.webView.layer.opaque = NO;
This is the code I use to show the panel:
- (void) showPanel
{
NSPoint mouseLocation = [NSEvent mouseLocation];
NSEnumerator *screenEnumerator = [[NSScreen screens] objectEnumerator];
NSScreen *screen;
while ((screen = [screenEnumerator nextObject]) && !NSMouseInRect(mouseLocation, screen.frame, NO))
;
NSRect statusFrame = [[self.statusItem valueForKey:#"window"] frame];
NSRect winFrame = [self.window frame];
NSRect screenFrame = [screen frame];
NSPoint p = NSMakePoint(statusFrame.origin.x, screenFrame.size.height + screenFrame.origin.y - 32);
if ((p.x + winFrame.size.width) > (screenFrame.origin.x + screenFrame.size.width)) {
p.x = screenFrame.origin.x + screenFrame.size.width - winFrame.size.width - 30;
}
[self.window setFrameTopLeftPoint:p];
[self.window setIsVisible:YES];
[NSApp activateIgnoringOtherApps:YES];
[self.window makeKeyAndOrderFront:self];
}
But doesn't seem to be showing any rounded corners in the frame. Any ideas?
I still can't make suitable view because of white corners, but I made WebView's corners rounded. I wrote this just in applicationDidFinishLaunching method:
self.webView.wantsLayer = YES;
self.webView.layer.cornerRadius = 50.0f;
self.webView.layer.masksToBounds = YES;
[self.webView.mainFrame.frameView setAllowsScrolling:NO];
and as you can see rounding is works, but there also white places in corners, and I don't know how to deal with them
I am adding some annotations to a MKMapView and these annotations have a UIImageView, loaded asynchronously with AFNetworking, as left callout accessory view. Here's the implementation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *identifier = #"MapAnnotation";
if ([annotation isKindOfClass:[MapAnnotation class]]) {
MKAnnotationView *annotationView = (MKAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:#"map_pin"];
UIImageView *userAvatar = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
[userAvatar setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=small",[[(MapAnnotation *)annotation user] facebookID]]] placeholderImage:[UIImage imageNamed:#"user_placeholder"]];
userAvatar.layer.cornerRadius = 4.0;
userAvatar.layer.masksToBounds = YES;
userAvatar.layer.borderColor = [[UIColor blackColor] CGColor];
userAvatar.layer.borderWidth = 1;
annotationView.leftCalloutAccessoryView = userAvatar;
UIButton *rightCallout = [UIButton buttonWithType:UIButtonTypeInfoLight];
annotationView.rightCalloutAccessoryView = rightCallout;
}
annotationView.annotation = annotation;
return annotationView;
}
return nil;
}
The problem here is: sometimes (not all the times) when annotations for different users are loaded into the map, they show the same image for all of them.
Let's say I have to load two annotations with this information:
Annotation 1
Name (title): Joshua
Datetime (subtitle): 19/06, 11:00
Image: www.myurl.com/joshua.jpg
Annotation 2
Name (title): Mathew
Datetime (subtitle): 10/06, 20:00
Image: www.myurl.com/mathew.jpg
Sometimes they are shown with title and subtitle correctly but the image loaded is the same for all of them (joshua's image or vice versa).
Am I missing something here is this method?
The call to dequeueReusableAnnotationViewWithIdentifier: will at the first call return nil which will satisfy annotationView == nil and set up your annotation view. So all the following calls to dequeueReusableAnnotationViewWithIdentifier: will return the first created annotation view with the assigned avatar image.
So [userAvatar setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=small",[[(MapAnnotation *)annotation user] facebookID]]] placeholderImage:[UIImage imageNamed:#"user_placeholder"]]; is only called once.
You need to move annotation specific changes to the annotation view outside the "if nil" setup scope.
So you should instead set the userAvatar image each time the mapview ask for a annotationView.
So something like this:
MKAnnotationView *annotationView = (MKAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:#"map_pin"];
UIImageView *userAvatar = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
userAvatar.layer.cornerRadius = 4.0;
userAvatar.layer.masksToBounds = YES;
userAvatar.layer.borderColor = [[UIColor blackColor] CGColor];
userAvatar.layer.borderWidth = 1;
annotationView.leftCalloutAccessoryView = userAvatar;
UIButton *rightCallout = [UIButton buttonWithType:UIButtonTypeInfoLight];
annotationView.rightCalloutAccessoryView = rightCallout;
}
[((UIImageView *)annotationView.leftCalloutAccessoryView) setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=small",[[(MapAnnotation *)annotation user] facebookID]]] placeholderImage:[UIImage imageNamed:#"user_placeholder"]];
This will assign the correct image each time the map view asks for an annotation view.
Cheers
Morten
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
//if it's user location, return nil
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
//try to dequeue an existing pin view first
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
pinView.animatesDrop = YES;
pinView.canShowCallout = YES;
pinView.pinColor = MKPinAnnotationColorRed;
//button on the right for popup for pins
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[rightButton addTarget:self
action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = rightButton;
//zoom button on the left of popup for pins
UIButton* leftButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
[leftButton setTitle:annotation.title forState:UIControlStateNormal];
[leftButton addTarget:self
action:#selector(zoomToLocation:) forControlEvents:UIControlEventTouchUpInside];
pinView.leftCalloutAccessoryView = leftButton;
return pinView;
}
//for map view annotation right button
-(void)showDetails:(id)sender{
NSLog(#"Annotation Click");
//fypAppDelegate *appDelegate = (fypAppDelegate *)[[UIApplication sharedApplication] delegate];
//Attraction *attraction = (Attraction *)[appDelegate.attractions objectAtIndex:sender];
infoViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"info"];
self.infoView = viewController;
[self.navigationController pushViewController:infoView animated:true];
}
//for map view annotation left button
-(void)zoomToLocation:(id)sender{
NSLog(#"Annotation Click");
}
Above is the delegate for the map annotations. I am able to show the pins and show the map annotation view but I don't know how to link the button events to the next view (infoViewController).
So as you guys can see, the right button is the one I want to use to enable user to view more information about that place while the left button, I want to allow user to zoom in into the coordinates of that pin.
The data are from the database I've created. Below is how I did it just for reference (in case you guys might need it)
-(void)putPins
{
fypAppDelegate *appDelegate = (fypAppDelegate *)[[UIApplication sharedApplication] delegate]; //get data
[appDelegate readTopAttractions];
int i = 0;
int count = appDelegate.attractions.count;
self.mapAnnotations = [[NSMutableArray alloc] initWithCapacity:appDelegate.attractions.count];
while (i < count) {
Attraction *attraction = (Attraction *)[appDelegate.attractions objectAtIndex:i];
i++;
//Set coordinates for pin
CLLocationCoordinate2D location;
location.latitude = (double)[[attraction xCoor] doubleValue];
location.longitude = (double)[[attraction yCoor] doubleValue];
MapPin *mapPin = [[MapPin alloc] init];
[mapPin setCoordinate:location];
[mapPin setName: [attraction name]];
NSString *desc = [attraction description];
int i = 0, position;
while(i < 50){
if ([desc characterAtIndex:i] == ' '){
position = i;
i++;
}
else
i++;
}
desc = [#"" stringByAppendingFormat:#"%#%#", [desc substringToIndex:position], #"..."];
[mapPin setDescription: desc];
[self.mapAnnotations addObject:mapPin];
}
[self.mapView addAnnotations:self.mapAnnotations];
}
please do tell me if you guys need more details.
Thank you! =)
In your showDetails: and zoomToLocation: methods, you can get a reference to the annotation whose callout button was tapped by doing the following:
MapPin *ann = (MapPin *)[mapView.selectedAnnotations objectAtIndex:0];
In zoomToLocation: you can then zoom in to that annotation using:
[mapView setRegion:
MKCoordinateRegionMakeWithDistance(ann.coordinate, 500, 500)
//500 meters vertical span, 500 meters horizontal span
animated:YES];
In showDetails:, you can pass ann or its properties to the detail view.
By the way, instead of calling custom methods using addTarget in viewForAnnotation, you can use the map view's calloutAccessoryControlTapped delegate method which gives more direct access to the annotation that was tapped. For example:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
MapPin *ann = (MapPin *)view.annotation;
if (control == view.rightCalloutAccessoryView)
{
NSLog(#"calloutAccessoryControlTapped: control=RIGHT");
//show detail view (or you can call your custom method here)...
}
else
if (control == view.leftCalloutAccessoryView)
{
NSLog(#"calloutAccessoryControlTapped: control=LEFT");
//zoom in (or you can call your custom method here)...
}
else
{
NSLog(#"calloutAccessoryControlTapped: unknown control");
}
}
Make sure you remove the addTarget calls from viewForAnnotation if you decide to use the calloutAccessoryControlTapped delegate method.
You want to zoom in to the particular pin? Is that right?
Therefore you can use the setRegion:animated: - method from MKMapView.
Example:
mapView = MKMapView
location = CLLLocationCoordinate2D
METERS_PER_MILE = 1609.344 (defined as a Constant)
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(location, 0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:region];
[mapView setRegion:adjustedRegion animated:YES];
AppleDocs
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html
http://developer.apple.com/library/IOs/#documentation/MapKit/Reference/MapKitDataTypesReference/Reference/reference.html
I have created Custom Annotation with following:
-(MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
MKPinAnnotationView *view = nil;
if (annotation != mapView.userLocation)
{
view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"myAnnotationIdentifier"];
if (!view)
view = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"myAnnotationIdentifier"];
if (((CustomAnnotation *)annotation).annotationType == 1)
{
view.image = [UIImage imageNamed:#"type1.png"];
view.rightCalloutAccessoryView = nil;
view.canShowCallout = YES;
}
else
{
view.image = [UIImage imageNamed:#"type2.png"];
view.rightCalloutAccessoryView = nil;
view.canShowCallout = YES;
}
}
return view;
}
Problem: When User press and hold for 2 seconds on any Annotation Image (type1 or type2), Image gets replaced by Red PushPin(Default for iPhone MKPinAnnotationView).
I want to avoid this replacement. How can I do so?
Instead of declaring and creating an MKPinAnnotationView, declare and create a plain MKAnnotationView.
The MKPinAnnotationView likes to default to the red pin which is what it's for.
Use didDeselectAnnotationView and didSelectAnnotationView and reselect the image as you did by :-
view.image = [UIImage imageNamed:#"type2.png"];
I have a MKMapview loading with maybe 5 annotations (right now). It loads fine, with the annotations as well. Each annotation contains the correct left and right callout. However after a while (maybe 2 minutes) i often get a EXC_BAD_ACCESS crash, on the left callout of an annotation...
- (MKAnnotationView *) mapView:(MKMapView *)thisMapView
viewForAnnotation:(MapAnnotations *)annotation
{
static NSString *MapIdentifier = #"MapIdentifier";
UIImageView *myImageView;
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[thisMapView dequeueReusableAnnotationViewWithIdentifier:MapIdentifier];
if(annotationView == nil)
{
NSString * id = [NSString stringWithFormat:#"%d", (annotation).tag];
NSString * postPhoto = [NSString stringWithFormat:#"id=%#",id];
NSString * hostStrPhoto = #"http://domain.com/get_image.php?";
hostStrPhoto = [hostStrPhoto stringByAppendingString:postPhoto];
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:hostStrPhoto]];
myImageView = [[UIImageView alloc] initWithImage:[UIImage imageWithData: imgData]];
myImageView.frame = CGRectMake(0,0,31,31);
annotationView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:MapIdentifier] autorelease];
}
annotationView.animatesDrop=TRUE;
annotationView.canShowCallout = YES;
annotationView.leftCalloutAccessoryView = myImageView; //<--where I am getting the error, after all the annotations have loaded.
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
[myImageView autorelease];
}
I am thinking maybe my app is still trying to load annotations, but I can't figure out why. As well i am getting some memory warnings when the map is loaded, so perhaps I am not releasing some objects the way i should be, i'm still kind of new to how the memory management works, so any suggestions would be helpful.
If you end up re-using an annotation view, myImageView isn't created, yet you're releasing it. Set myImageView to nil at the top.
- (MKAnnotationView *) mapView:(MKMapView *)thisMapView viewForAnnotation:(MapAnnotations *)annotation {
static NSString *MapIdentifier = #"MapIdentifier";
UIImageView *myImageView = nil;
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[thisMapView dequeueReusableAnnotationViewWithIdentifier:MapIdentifier];
if(annotationView == nil) {
NSString * id = [NSString stringWithFormat:#"%d", (annotation).tag];
NSString * postPhoto = [NSString stringWithFormat:#"id=%#",id];
NSString * hostStrPhoto = #"http://domain.com/get_image.php?";
hostStrPhoto = [hostStrPhoto stringByAppendingString:postPhoto];
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:hostStrPhoto]];
myImageView = [[UIImageView alloc] initWithImage:[UIImage imageWithData: imgData]];
myImageView.frame = CGRectMake(0,0,31,31);
annotationView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:MapIdentifier] autorelease];
}
annotationView.animatesDrop=TRUE;
annotationView.canShowCallout = YES;
annotationView.leftCalloutAccessoryView = myImageView; //<--where I am getting the error, after all the annotations have loaded.
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
[myImageView release];
}