objective c - hide a custom annotation view - objective-c

I want to have a custom Annotation view that behaves exactly as the standard one, but mine needs to have an image inside and several texts, that's why I've implemented the tutorial on http://developer.apple.com/library/ios/#samplecode/WeatherMap/Introduction/Intro.html
But my problem is that I want the annotation view to hide and just show a pin, same thing as the default annotation view behaves but all annotations are showing and I cant figure out a way to hide them.
Any ideas?
Thanks.
[EDIT]
My current implementation of viewForAnnotation is:
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation{
NSLog(#"Item añadido");
static NSString *AnnotationViewID = #"annotationViewID";
CustomMKAnnotationView *annotationView =
(CustomMKAnnotationView *)[mapa dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[[CustomMKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID] autorelease];
}
annotationView.annotation = annotation;
return annotationView;
}
Becuase I need the standard bubble but with an image and a couple of UILabels. But I would like to keep the standard behaviour, that is, there's a pin when the bubble is not showing, and when you tap it shows the bubble. The content of my custom bubble is implemented in "CustomMKAnnotationView".
Which is as follows:
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self != nil)
{
CGRect frame = self.frame;
frame.size = CGSizeMake(10.0, 10.0);
self.frame = frame;
// self. = [super pincolor];
self.backgroundColor = [UIColor clearColor];
self.centerOffset = CGPointMake(10.0, 10.0);
}
return self;
}
- (void)drawRect:(CGRect)rect{
CustomMKAnnotation *custom = (CustomMKAnnotation *)self.annotation;
if (custom != nil)
{
NSLog(#"El nombre es: %#", [custom nombre]);
UILabel *nombre = [[UILabel alloc]init];
UILabel *media = [[UILabel alloc]init];
PDColoredProgressView *barrita = [[PDColoredProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleDefault];
[barrita setTintColor:[UIColor colorWithRed:0.6 green:0.83 blue:0.91 alpha:1.0f]];
nombre.textColor = [UIColor whiteColor];
media.textColor = [UIColor whiteColor];
nombre.font = [UIFont fontWithName:#"DIN-Bold" size:14];
media.font = [UIFont fontWithName:#"DIN-Medium" size:12];
CGSize size = [[custom nombre] sizeWithFont:nombre.font constrainedToSize:CGSizeMake(300, 20) lineBreakMode:nombre.lineBreakMode];
NSLog(#"el ancho es: %f y alto %f", size.width, size.height);
nombre.backgroundColor = [UIColor clearColor];
media.backgroundColor = [UIColor clearColor];
nombre.text = [custom nombre];
barrita.progress = [custom gente];
media.text = [NSString stringWithFormat:#"Media %# años", [custom media]];
UIImageView *fondo = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"bubble_map.png"]];
nombre.frame = CGRectMake(10, 10, size.width, size.height);
media.frame = CGRectMake(10, size.height + 10, size.width, size.height);
barrita.frame = CGRectMake(10, media.frame.origin.y + 20, size.width, 10);
fondo.frame = CGRectMake(-((size.width+ 20.0f)/2), -((size.height +10)*2 + 20)-10, size.width+ 20.0f, (size.height +10)*2 + 20);
fondo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
nombre.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[fondo addSubview:nombre];
[fondo addSubview:media];
[fondo addSubview:barrita];
[self addSubview:fondo];
[fondo release];
[nombre release];
[media release];
}
}

If you mean hiding the details of pin, have you tried creating a custom MKPinAnnotationView and set its property of canShowCallout=NO; ?
In your mapview delegate method :
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView*pinView;
if([annotation isKindOfClass:[<yourannotationclass> class]])
{
static NSString*annoIdentifier=#"AnnotationIdentifier";
pinView=(MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:annoIdentifier];
if(pinView==nil)
{
pinView=[[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:annoIdentifier]autorelease ];
}
pinView.animatesDrop=NO;
pinView.canShowCallout=NO;
pinView.pinColor=MKPinAnnotationColorRed;
}
return pinView;
}

Related

MapView annotation not showing Images and Detail Disclosure Button - iOS Mapkit Xcode 6 Objective C

I am adding 2 annotations in mapview with leftcalloutaccessoryview (with an image) and rightcalloutacessoryview (with detail disclosure button). The problem is that it is working fine but only for one annotation, not for both. It shows one annotation with image and detail disclosure button that can be tapped while second annotation shows only title, no image and no detail disclosure button and it can not be tapped. Here is my code.
-(void)viewDidLoad{
[super viewDidLoad];
myLocationManager=[[CLLocationManager alloc] init];
geocoder = [[CLGeocoder alloc] init];
myLocationManager.delegate=self;
myLocationManager.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;
myLocationManager.distanceFilter=10.0;
[myLocationManager startUpdatingLocation];
mapView = [[MKMapView alloc]initWithFrame:
CGRectMake(10, 255, 300, 205)];
mapView.delegate = self;
mapView.centerCoordinate = CLLocationCoordinate2DMake(37.32, -122.03);
mapView.mapType = MKMapTypeStandard;
[self startAddingAnnottaions];
[self.view addSubview:mapView];
}
//startAddingAnnotations now
-(void)startAddingAnnottaions{
//first annotation
CLLocationCoordinate2D location;
location.latitude = (double) 37.331768;
location.longitude = (double) -122.020039;
MapAnnotation *newAnnotation = [[MapAnnotation alloc]
initWithTitle:#"Apple Head quaters" subtitle:#"subtitle" andCoordinate:location];
[mapView addAnnotation:newAnnotation];
//second annotation
CLLocationCoordinate2D location2;
location2.latitude = (double) 37.35239;
location2.longitude = (double) -122.025919;
MapAnnotation *newAnnotation2 = [[MapAnnotation alloc]
initWithTitle:#"Test Annotation" subtitle:#"parse" andCoordinate:location2];
[mapView addAnnotation:newAnnotation2];
}
//didAddAnnotationViews
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView *annotationView = [views objectAtIndex:0];
id <MKAnnotation> mapPoint = [annotationView annotation];
annotationView.canShowCallout = YES;
annotationView.calloutOffset = CGPointMake(0, 32);
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.rightCalloutAccessoryView = rightButton;
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"orageSquare.png"]];
annotationView.leftCalloutAccessoryView = iconView;
MKCoordinateRegion region;
region.center = [mapPoint coordinate];
MKCoordinateSpan span;
span.latitudeDelta = 0.0144927536; // 0.0144927536 is equivalent to 1 mile
span.longitudeDelta = 0.0144927536;
region.span = span;
[mv setRegion:region animated:YES];
[mv selectAnnotation:mapPoint animated:YES];
}
//callout Accessory Control Tapped
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
id <MKAnnotation> annotation = [view annotation];
NSLog(#"Right Button Pressed");
[self performSegueWithIdentifier:#"mapToOtherInfo" sender:self];
}
What am I doing wrong? It should show multiple annotations with image and detail disclosure button. Why is it showing only one annotation with them? sometimes first one works fine, sometimes second one does but both don't work fine together.
You should set leftCalloutAccessoryView and rightCalloutAccessoryView property in viewForAnnotation method, not didAddAnnotationViews. Then you can show both annotation.
example:
- (MKAnnotationView *)mapView:(MKMapView*)mapView
viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation == mapView.userLocation) {
return nil;
}
MKPinAnnotationView *annotationView;
NSString *identifier = #"Pin";
annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (nil == annotationView) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
}
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"frame_blue.png"]];
annotationView.leftCalloutAccessoryView = iconView;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotaionView;
}

Custom MKAnnotationView masksToBounds=YES and canShowCallout=YES exception

How to I properly set a radius on a custom MKAnnotationView and allow callouts? This throws an exception:
From my custom MKAnnotationView class:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.frame = CGRectMake(0, 0, 30, 30);
self.opaque = NO;
self.multipleTouchEnabled = NO;
self.backgroundColor = [UIColor whiteColor];
self.layer.cornerRadius = 5;
self.layer.masksToBounds = YES;
self.layer.borderColor = [UIColor blueColor].CGColor;
self.layer.borderWidth = 1.0f;
self.layer.shadowOffset = CGSizeMake(1, 0);
self.layer.shadowColor = [[UIColor blackColor] CGColor];
self.layer.shadowRadius = 5;
self.layer.shadowOpacity = .25;
}
return self;
}
Within my class that presents the map view:
- (MKAnnotationView *)mapView:(MKMapView *)mView viewForAnnotation:(id <MKAnnotation>)annotation
{
// logic to dequeue annotation views, etc.
annotationView.canShowCallout = YES;
return annotationView;
}
Exceptions:
* Terminating app due to uncaught exception 'NSGenericException', reason: '> cannot show callout with clipsToBounds enabled'
* First throw call stack:
(0x1c04012 0x1689e7e 0x4eab5f 0x4ebcaf 0x4ebaea 0x4ebf03 0x4d7e24 0x4d7e54 0x4da610 0x5a7e 0x221853f 0x222a014 0x221a7d5 0x1baaaf5 0x1ba9f44 0x1ba9e1b 0x1a617e3 0x1a61668 0x5cdffc 0x29ad 0x28d5)
libc++abi.dylib: terminate called throwing an exception
(lldb)
I found a solution. I created an OuterAnnotationView with a clear color and added a subview to the OuterAnnotationView on initialization. The subview that I added (the inner) I can set
a cornerRadius and masksToBounds=YES and everything works now.
-(MKAnnotationView *)annotationView{
annotationView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:profilePictureString]]];
annotationView.canShowCallout = NO;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeInfoDark];
annotationView.frame = CGRectMake(0, 0, 50,50);
annotationView.layer.cornerRadius = 25;
annotationView.layer.masksToBounds = YES;
annotationView.contentMode = UIViewContentModeScaleAspectFit;
return annotationView;
}
In your code, re write it with:
self.layer.masksToBounds = NO;

Map annotation not showing accessory view properly

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

UIScrollView and UIPageControl, what am I doing wrong?

I have a class which is predefining some labels and binding their values in a UIScrollView.
I've managed to show those labels, but now I'm stuck at putting a label at the 2nd part of the ScrollView.
I've pushed my project to gitHub.
I can change the label's place on the already visible part, but I must be overlooking something.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.title = _detail.name;
UIColor *bgColor = [UIColor blackColor];
UIColor *txtColor = [UIColor grayColor];
CGRect frame;
frame.origin.x = 0;
frame.origin.y = 0;
frame.size.width = _scrollView.frame.size.width *2;
NSString *phoneNr = (_detail.phoneNr == nil) ? #"Not specified" : _detail.phoneNr;
_telLabel = [self prepareLabel:phoneNr textColor:txtColor bgColor:bgColor page:0 y:telNrYAxis];
_webLabel = [self prepareLabel:#"Visit website" textColor:txtColor bgColor:bgColor page:0 y:websiteYAxis];
_detail.address = [_detail.address stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"\n\t "]];
NSArray *addressArrComponents = [_detail.address componentsSeparatedByString:#","] ;
_addressLabel = [self prepareLabel:[addressArrComponents componentsJoinedByString:#"\n"] textColor:txtColor bgColor:bgColor page:0 y:addressYAxis];
UILabel *lbl = [self prepareLabel:#"Derp" textColor:txtColor bgColor:bgColor page:1 y:0];
_detailView = [[UIView alloc] initWithFrame:frame];
_detailView.backgroundColor = [UIColor blackColor];
[_detailView addSubview:_webLabel];
[_detailView addSubview:_addressLabel];
[_detailView addSubview:_telLabel];
[_detailView addSubview:lbl];
[_scrollView addSubview:_detailView];
NSLog(#"%f",self.view.frame.size.height - (_scrollView.frame.origin.y + _scrollView.frame.size.height) );
_pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height - 250 , self.view.frame.size.width/4, 120)];
_pageControl.numberOfPages=2;
_pageControl.currentPage=0;
[_pageControl addTarget:self action:#selector(pageChange:) forControlEvents:UIControlEventTouchDown];
_scrollView.contentSize = CGSizeMake(800,800);
_scrollView.delegate=self;
_scrollView.backgroundColor = [UIColor blackColor];
_scrollView.pagingEnabled=YES;
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.showsVerticalScrollIndicator = NO;
_scrollView.scrollsToTop = NO;
[self pageChange:0];
[self.view addSubview:_pageControl];
// Do any additional setup after loading the view.
}
-(UILabel*)prepareLabel:(NSString*) text textColor:(UIColor*)textColor bgColor:(UIColor*)backgroundColor page:(int)page y:(int) yPos{
int lines = [[text componentsSeparatedByString:#"\n"] count];
CGRect labelFrame = CGRectMake(_detailView.frame.size.width * page +20,yPos,self.view.frame.size.width, [UIFont systemFontSize]*lines);
UILabel *returnLabel = [[UILabel alloc] initWithFrame:labelFrame];
returnLabel.text = text;
returnLabel.backgroundColor = backgroundColor;
returnLabel.textColor = textColor;
[returnLabel setNumberOfLines:lines];
[returnLabel sizeToFit];
return returnLabel;
}
- (void)loadScrollViewWithPage:(int)page {
NSLog(#"Derped");
}
-(IBAction)pageChange:(id)sender{
int page=_pageControl.currentPage;
CGRect frame = _scrollView.frame;
frame.origin.x = _scrollView.frame.size.width * page;
frame.origin.y = 0;
//CGRect frame= (page == 0) ? _detailFrame : _reviewFrame;
NSLog(#"%f",frame.origin.x);
[_scrollView scrollRectToVisible:frame animated:YES];
}
The delegate -(IBAction)pageChange:(id)sender gets fired, but I must be doing something wrong with the frames somewhere :s
Please take a look!
Try to implement this method may help you :
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat pageWidth = self.scrollView.frame.size.width;
float fractionalPage = self.scrollView.contentOffset.x / pageWidth;
NSInteger page = lround(fractionalPage);
self.pageControl.currentPage = page;
}

How do I add a UIButton or UISwitch in tableView:viewForFooterInSection

I'm trying to understand how to add a label with a UISwitch or other controller to a footer (or header) in a sectioned tableView. Any help would be greatly appreciated. Thank you in advance!
Okay, after searching and working at it I've done the following:
// Need to refactor so that the label is Public Sharing and Priviate Sharing and the actions work for each switch
- (UIView *) tableView: (UITableView *) tableView
viewForFooterInSection: (NSInteger) section
{
if (section == 0 || section == 1) {
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
UIView* footerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, 44.0)] autorelease];
footerView.autoresizesSubviews = YES;
footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
footerView.userInteractionEnabled = YES;
footerView.hidden = NO;
footerView.multipleTouchEnabled = NO;
footerView.opaque = NO;
footerView.contentMode = UIViewContentModeScaleToFill;
// Add the label
UILabel* footerLabel = [[UILabel alloc] initWithFrame:CGRectMake(150.0, -5.0, 120.0, 45.0)];
footerLabel.backgroundColor = [UIColor clearColor];
footerLabel.opaque = NO;
footerLabel.text = #"Sharing";
footerLabel.textColor = [UIColor tableHeaderAndFooterColor];
footerLabel.highlightedTextColor = [UIColor tableHeaderAndFooterColor];
footerLabel.font = [UIFont boldSystemFontOfSize:17];
footerLabel.shadowColor = [UIColor whiteColor];
footerLabel.shadowOffset = CGSizeMake(0.0, 1.0);
[footerView addSubview: footerLabel];
[footerLabel release];
// Add the switch
UISwitch* footerSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(215.0, 5, 80.0, 45.0)];
[footerView addSubview: footerSwitch];
// Return the footerView
return footerView;
}
else return nil;
}
// Need to call to pad the footer height otherwise the footer collapses
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
switch (section) {
case 0:
case 1:
return 40.0;
default:
return 0.0;
}
}
I hope this is correct and if this helps anyone else please vote this up. Cheers!
i think you need to autorelease the uiview-