I have create BubbleView in mapview. In bubble i have put the button but i have not click on button.
How can i implement please help me.
I have tried.......
customCalloutView.h
#import <UIKit/UIKit.h>
#interface customCalloutView : UIView
#property (nonatomic, retain) IBOutlet UIButton *BubbleBtn;
customCalloutView.m
#import "customCalloutView.h"
#implementation customCalloutView
{
}
#end
Delegate method of mapview in anotherclass
- (MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *identifier=#"MyAnnotation";
NSLog(#"anotioni s:%#",annotation);
//CLLocationCoordinate2D pinCoordinate = [self.pickupLocationView convertPoint:CGPointMake(self.pickupLocationView.frame.size.width / 2, self.pickupLocationView.frame.size.height) toCoordinateFromView:self.view];
MKAnnotationView *annotationView=(MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annotationView)
{
annotationView=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.image=[UIImage imageNamed:#"mapPin"];
} else
{
annotationView.annotation=annotation;
}
return annotationView;
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
customCalloutView *callOutView=nil;
callOutView.userInteractionEnabled=YES;
if (callOutView == nil)
{
NSArray *nib=[[NSBundle mainBundle]loadNibNamed:#"customCalloutView" owner:self options:nil];
callOutView=[nib objectAtIndex:0];
}
[callOutView.BubbleBtn addTarget:self action:#selector(BtnDetailclick:) forControlEvents:UIControlEventTouchUpInside];
CGRect callOutViewFrame=callOutView.frame;
callOutViewFrame.origin=CGPointMake(-callOutViewFrame.size.width/2+14 , -callOutViewFrame.size.height);
callOutView.frame=callOutViewFrame;
// [callOutView.BtnDetail setTitle:#"Change" forState:UIControlStateNormal];
[view addSubview:callOutView];
}
-(IBAction)BtnDetailclick:(UIButton *)sender
{
NSLog(#"Hello");
}
Related
I have a custom annotation view class which is like
#interface MyAnnotationView : MKAnnotationView
#property (nonatomic, strong) UIImageView *imageView;
#end
and then I use it in the MKMapView like :
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
MKAnnotationView *annotationView = nil;
MyAnnotationView *view = (MyAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:MyAnnotationViewIdentifier];
if (view == nil) {
view = [[MyAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:MyAnnotationViewIdentifier];
}
view.imageView.image = myImage;
annotationView = view;
return annotationView;
}
This code works as expected till iOS 11, but in iOS 12 I dont see the image anymore. What am I missing? Any tips appreciated.
I have a cluster of annotation pins in map view. When I clicked on the pin I get the index of that pin. I want that if I click on the pin than all the pins are hide except that on which user clicked and if again I click on that pin all the pins are shown.
Here is the code in which I got the index of the selected pin.
CPointAnnotation *cAnno=(CPointAnnotation*)view.annotation;
NSInteger index=cAnno.index;
if (index<hospitalsArry.count) {
selectedHospital=[hospitalsArry objectAtIndex:index];
if (selectedIndex==index) {
selectedIndex=-1;
return;
}else{
selectedIndex=index;
[[self.mapView viewForAnnotation:cAnno] setHidden:NO];
}
CustomAnnotation.h
#import <MapKit/MapKit.h>
#interface CustomAnnotation : NSObject <MKAnnotation>
#property (nonatomic,readonly)CLLocationCoordinate2D coordinate;
#property (nonatomic, copy)NSString *title;
#property (nonatomic, strong)MKAnnotationView *annotaitonView;
-(id)initWithTitle:(NSString *)newTitle coordinates:(CLLocationCoordinate2D)newCoordinate;
-(MKAnnotationView *)createAnnotationView;
#end
CustomAnnotation.m
#implementation CustomAnnotation
-(id)initWithTitle:(NSString *)newTitle coordinates:(CLLocationCoordinate2D)newCoordinate
{
if (self = [super init]) {
_title = newTitle;
_coordinate = newCoordinate;
}
return self;
}
-(MKAnnotationView *)createAnnotationView
{
MKAnnotationView *annView=[[MKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:#"MyCustomAnnoation"];
annView.enabled=TRUE;
annView.canShowCallout=TRUE;
annView.image=[UIImage imageNamed:#"map-pin-marker-circle-128.png"];
return annView;
}
#end
in MapViewController.m
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
return nil;
}
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
CustomAnnotation *myAnn=(CustomAnnotation *)annotation;
MKAnnotationView *annView=[mapView dequeueReusableAnnotationViewWithIdentifier:#"MyCustomAnnoation"];
if (annView == nil) {
annView=[myAnn createAnnotationView];
}
else
{
annView.annotation=myAnn;
}
myAnn.annotaitonView=annView;
return annView;
}
else
return nil;
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
[self hideOtherPinsByIgnoringThis:view];
}
-(void)hideOtherPinsByIgnoringThis:(MKAnnotationView *)ann
{
NSArray *arrAllPins=[self.myMapView annotations];
//Find selected Annotation View in all pins on map
NSMutableArray *removeAnn=[[NSMutableArray alloc]init];
for (CustomAnnotation *annotation in arrAllPins)
{
if (annotation.annotaitonView != ann) {
[removeAnn addObject:annotation];
}
}
[self.myMapView removeAnnotations:removeAnn];
}
So, I've created a custom callout that appears over the selected annotation. Everything works exactly how I want--the only problem is after I've dropped another pin of the same type, then all the past pins will display the same information. For example, I may have a pin drop that displays in the callout "McDonalds" and the next pin that drops displays "Starbucks". Now all my previously dropped pins will display "Starbucks".
I'm currently attempting to store information in the annotation's subtitle property and then displaying that through a formatted string onto my custom UIView's Label...It works but I need the annotation's information to never change. There must be something I'm missing or do not understand. Any help will be much appreciated.
I've posted all the code I believe to be relevant below. Thank you!
Custom Callout.h
#import <UIKit/UIKit.h>
#interface PinView : UIView
{
UIView *view;
UILabel *theValueLabel;
}
#property (nonatomic, retain) IBOutlet UIView *view;
#property (nonatomic, retain) IBOutlet UILabel *theValueLabel;
#end
Custom Callout.m
#import "PinView.h"
#implementation PinView
#synthesize theValueLabel;
#synthesize view;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
UIView *nib = [[[UINib nibWithNibName:#"customView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0];
[self addSubview:nib];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
if (self.subviews.count == 0) {
UIView *nib = [[[UINib nibWithNibName:#"customView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0];
[self addSubview:nib];
}
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self setup];
}
- (void)setup {
self.theValueLabel.text = #"foo";
}
in my main View Controller.m
#interface BreadTrailViewController ()<CLLocationManagerDelegate, MKMapViewDelegate, MFMailComposeViewControllerDelegate>
{
PinView *aView
MKPointAnnotation *Pin1;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
if (location != nil)
{
Pin1 = [[MKPointAnnotation alloc] init];
Pin1.title = #"Venue";
Pin1.subtitle = [NSString stringWithFormat:#"Venue Name: %#\n%f,%f\nAddress: %#",revGeocodeVenue, lat, lng, revGeocodeAddress];
Pin1.coordinate = location.coordinate;
[self.mapView addAnnotation:Pin1];
}
}
- (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]])
{
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = NO;
} else {
pinView.annotation = annotation;
}
if ([[annotation title] containsString:#"Venue"])
{
pinView.pinTintColor = [UIColor greenColor];
}
return pinView;
}
return nil;
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
aView = [[PinView alloc] initWithFrame:CGRectMake( 0, 0, 300, 350)];
aView.layer.cornerRadius = 20;
aView.layer.masksToBounds = YES;
aView.center = CGPointMake(view.bounds.size.width*0.5f, -aView.bounds.size.height*0.35f);
//Using the Pin's subtitle to store the data string and display on PinView
if ([[view.annotation title] containsString:#"Venue"])
{
aView.theValueLabel.text = Pin1.subtitle;
}
[view addSubview:aView];
}
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
[aView removeFromSuperview];
}
I found the problem! I was using Pin1.subtitle when what I should be using is view.annotation.subtitle--everything is working perfectly now. I hope this helps someone else!
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
aView = [[PinView alloc] initWithFrame:CGRectMake( 0, 0, 300, 350)];
aView.layer.cornerRadius = 20;
aView.layer.masksToBounds = YES;
aView.center = CGPointMake(view.bounds.size.width*0.5f, -aView.bounds.size.height*0.35f);
//Using the Pin's subtitle to store the data string and display on PinView
if ([[view.annotation title] containsString:#"Venue"])
{
aView.theValueLabel.text = view.annotation.subtitle;
}
[view addSubview:aView];
}
I need to put custom annotation views to mapview, and they need to be clickable. i need rather than classic callout, i will tap on the annotation and it will perform some functions.
I tried many things but still not achieved.
I found a really good implementation for you:
http://blog.asolutions.com/2010/09/building-custom-map-annotation-callouts-part-1/
there you can add buttons to calloutView with actions
or..
in mapView delegate you can customize the annotation, and the callout view:
viewForAnnotation:
Returns the annotation view associated with the specified annotation object, if any.
(MKAnnotationView *)viewForAnnotation:(id < MKAnnotation >)annotation
there is an example:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"loc"];
// Button
UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
button.frame = CGRectMake(0, 0, 23, 23);
annotationView.rightCalloutAccessoryView = button;
// Image and two labels
UIView *leftCAV = [[UIView alloc] initWithFrame:CGRectMake(0,0,23,23)];
[leftCAV addSubview : yourImageView];
[leftCAV addSubview : yourFirstLabel];
[leftCAV addSubview : yourSecondLabel];
annotationView.leftCalloutAccessoryView = leftCAV;
annotationView.canShowCallout = YES;
return annotationView;
}
EDITED ANSWER FOR CUSTOM PIN:
make a MKAnnotationView subclass
.h
#import <MapKit/MapKit.h>
#interface AnnotationView : MKAnnotationView
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier;
#end
.m
#import "AnnotationView.h"
#implementation AnnotationView
{
NSString *identifier;
}
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self != nil)
{
CGRect frame = self.frame;
frame.size = CGSizeMake(78.0, 35.0);
self.frame = frame;
self.backgroundColor = [UIColor clearColor];
self.centerOffset = CGPointMake(0, 0);
}
return self;
}
-(void) drawRect:(CGRect)rect
{
[[UIImage imageNamed:#"yourImage"]drawInRect:CGRectMake(0, 0, 78, 35)];
}
#end
then in the mapview delegate:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
if ([annotation isKindOfClass:[Annotation class]]) {
NSString* annotationIdentifier = #"yourAnnotation";
AnnotationView* customAnnotationView = (AnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (!customAnnotationView) {
customAnnotationView = [[AnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
customAnnotationView.canShowCallout = YES;
}
else{
customAnnotationView.annotation= annotation;
}
return customAnnotationView;
}
return nil;
}
Annotation class is my custom annotation class:
#interface Annotation : NSObject <MKAnnotation>
I hope this helps
There is a method on the mapViewDelegate: viewForMapView. In this method, you return a view. This view can be completely customized by you, e.g. you can add gestureregognizers to it to handle additional gestures beside tapping.
I'm developing an iOS app with latest SDK.
I have a selector on the following method and I need to pass another argument:
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"viewForAnnotation");
MKAnnotationView *annotationView = nil;
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
if ([annotation isKindOfClass:[ShopAnnotation class]])
{
// try to dequeue an existing pin view first
static NSString *ReusableAnnotationIdentifier = #"reusableShopAnnotationIdentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:ReusableAnnotationIdentifier];
if (!pinView)
{
// if an existing pin view was not available, create one
MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:ReusableAnnotationIdentifier];
customPinView.pinColor = MKPinAnnotationColorPurple;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
// add a detail disclosure button to the callout which will open a new view controller page
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}
else
{
pinView.annotation = annotation;
}
annotationView = pinView;
}
return annotationView;
}
I need to pass an object to showDetails::
// add a detail disclosure button to the callout which will open a new view controller page
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
This is how showDetails is implemented:
- (void) showDetails:(id)sender
{
NSLog(#"Show Details");
DetailViewController* mvc = [[DetailViewController alloc] initWithNibName:#"DetailViewController_iPhone" bundle:nil];
mvc.delegate = self;
[self presentModalViewController:mvc animated:YES];
}
This is ShopAnnotation interface:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <CoreData/CoreData.h>
#interface ShopAnnotation : NSObject <MKAnnotation>
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly, strong) NSString *title;
#property (nonatomic, readonly, strong) NSString *subtitle;
#property (nonatomic, readonly, strong) NSManagedObject* shop;
-(id)initWithCoordinate:(CLLocationCoordinate2D) c
title:(NSString *) t
subtitle:(NSString *) st
shop:(NSManagedObject*) shop;
#end
How can I add another argument to showDetails and how can I pass it?
showDetails will be:
- (void) showDetails:(id)sender shop:(NSManagedObject*)shop
And, what is this (id)sender? It is an annotation I could use to pass this NSManagedObject.
See how you're passing a "sender" parameter in your "showDetails:" method?
Why not subclass "UIButton" (e.g. name it "VansFannelButton") and give that new object's "#interface" a bonus ivar which can be your payload.
Then you can do:
- (void) showDetails: (VansFannelButton*) sender
{
if (sender)
{
// do something with the managed object payload
NSManagedObject * mObject = [sender payload];
}
}
Use Associated Objects for passing more argument to buttons's object
Refer associated-objects link.
You can try adding a property
int ID;
into your ShopAnnotation class, and when you are populating the ShopAnnotation class you can easily set your own unique ID. Then in
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if (!pinView)
{
// if an existing pin view was not available, create one
MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:ReusableAnnotationIdentifier];
customPinView.pinColor = MKPinAnnotationColorPurple;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
// add a detail disclosure button to the callout which will open a new view controller page
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
//Set tag of the button same as ID
rightButton.tag=((ShopAnnotation*)annotation).ID;
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}
}
And in you showDetails action you can do the following
- (void) showDetails:(id)sender
{
UIButton *btn=(UIButton*)sender;
ShopAnnotation *selectedAnnotation=nil;
for(ShopAnnotation *a in arrAnnotations){
if(a.ID == btn.tag){
selectedAnnotation=a; break;
}
}
// Use your ShopAnnotation for you further processing.
}
I hope this helps..
Thanks.