I want to create custom MKAnnotationView (with image) without a callout, but expandable after touch. Here is what i have in mind:
1) First the MKAnnotation looks like this:
2) Then after tap on it this should expand and looks like this:
I've started with customing MKAnnotationView and have a class:
#interface CustomPinAnnotation : NSObject <MKAnnotation>
The class have method:
-(MKAnnotationView*)annotationView {
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:self reuseIdentifier:#"AnnotationIdentifier"];
annotationView.enabled = YES;
annotationView.image = [[UIImage imageNamed:#"star"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
return annotationView;
}
And what i try to do is set a customView as a subview to the MKAnnotationView, but when i don't set The image it will not responding (this is pretty logical after i've think about it), but got the feeling that I'm doing something very nasty here, and should be a way to override MKAnnotationView somehow.
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
enemyAnnotationView.image = [UIImage imageNamed:#"firstImage.png"];
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
enemyAnnotationView.image = [UIImage imageNamed:#"SecondImage.png"];
}
Try like this first method is for the View for annotation that time your first image will be appears,
Second method will run when user select annotation
Related
I am just starting out wit MKMapKit and call outs. In particular, I have started to use mapView: viewForAnnotation: and a right accessory button. My problem is that the method only get called for newly added pins but not for those previously added to the map view. The call out opens but without a right accessory. Should this method be called for all pins?
-(MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *resuseId = #"WaypointMapViewVC";
MKAnnotationView *view =[mapView dequeueReusableAnnotationViewWithIdentifier:resuseId];
if (!view){
view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:resuseId];
view.canShowCallout=YES;
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
view.rightCalloutAccessoryView=rightButton;
} else {
view.annotation=annotation;
}
return view;
}
Am I doing something wrong here?
I have a bunch of pins on my map, some red and some green. The initial coloring is ok. However, when I use the map view and tap on some green ones, some reds will change to green. That probably happens when they are outside of the current view area and moved into the view area.
Ideas anyone?
Here's my code snip from :
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id < MKAnnotation >)annotation{
if(((MyAnnotation*)annotation).isGreen){
AnnotationViewID = #"MyAnnotationGreen";
}else{
AnnotationViewID = #"MyAnnotationRed";
}
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
}
You should use the isGreen property of your MyAnnotation object to assign the color to your MKPinAnnotationView object. The reuse code could give you an object that doesn't have all the properties set right, especially since you are using the exact same class under different identifier. You shouldn't rely on the validity of all property values of a dequeue object from view caches (such as uitableview dequeue).
do something like:
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
}
[annotationView setPinColor:(annotation.isGreen)? MKPinAnnotationColorGreen : MKPinAnnotationColorRed];
I know this question has been asked by others before and i have read them in this forum previously, but I have tried all the proposed approach without luck so far so I decided to post this question.
I have this piece of code below which is meant to change the pin icon on MKMapView. However the viewForAnnotation function doesn't even seem to get called by the MKMapView. People said that they got some problems with delegating the function to the file's owner which can be done by dragging the map view in .xib file to the file owner or defining myMap.delegate = self. I have done both ways but still get nothing.
Really appreciate for any help for my problem, thanks.
CODE:
- (MKPinAnnotationView*)myMap:(MKMapView*)myMap viewForAnnotation:(id<MKAnnotation>)annotation{
MKPinAnnotationView *pin = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"CustomPin"];
UIImage *icon = [UIImage imageNamed:#"bustour.png"];
UIImageView *iconView = [[UIImageView alloc] initWithFrame:CGRectMake(8,0,32,37)];
if(icon == nil)
NSLog(#"image: ");
else
NSLog(#"image: %#", (NSString*)icon.description);
[iconView setImage:icon];
[pin addSubview:iconView];
pin.canShowCallout = YES;
pin.pinColor = MKPinAnnotationColorPurple;
return pin;
}
DELEGATION
Your delegate method is named incorrectly as myMap:viewForAnnotation:.
The viewForAnnotation delegate method must be named mapView:viewForAnnotation: like this:
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id < MKAnnotation >)annotation
{
//code goes here...
}
The map view will look for that exact method name.
If not found, it won't call it and will create a default red pin instead.
You can change the name of the internal parameters but not the method name.
For example, this would also be ok:
- (MKAnnotationView *)mapView:(MKMapView *)myMap
viewForAnnotation:(id < MKAnnotation >)annotation
{
//code goes here...
}
import bellow class in your .h class..
#import <MapKit/MapKit.h>
and also add MKMapViewDelegate in your this class like bellow...
#interface PTAViewController : UIViewController<MKMapViewDelegate>{
///...... your code..
}
#end
As I understand, you setting outlet, not delegate. To set delegate do like that:
I can't figure out why a MKPinAnnotationView associated (in theory) with a MKPointAnnotation doesn't appear on the map. In fact, the pin appears but it isn't purple as it should be...
Here is the code:
MKPointAnnotation *myPersonalAnnotation= [[MKPointAnnotation alloc]init];
myPersonalAnnotation.title= [appDelegate.theDictionary objectForKey:#"theKey"];
myPersonalAnnotation.coordinate=CLLocationCoordinate2DMake(6.14, 10.7);
MKPinAnnotationView *myPersonalView=[[MKPinAnnotationView alloc] initWithAnnotation:myPersonalAnnotation reuseIdentifier:#"hello"];
myPersonalView.pinColor=MKPinAnnotationColorPurple;
[myMap addAnnotation:myPersonalAnnotation];
If you want to create an annotation view different from the default red pin, you have to create and return it in the map view's viewForAnnotation delegate method.
The map will automatically call the viewForAnnotation delegate method whenever it needs to show some annotation (either the built-in user location or annotations you add).
Remove the local creation of myPersonalView from before the call to addAnnotation and implement the viewForAnnotation method instead.
For example:
//in your current method...
MKPointAnnotation *myPersonalAnnotation= [[MKPointAnnotation alloc]init];
myPersonalAnnotation.title= [appDelegate.theDictionary objectForKey:#"theKey"];
myPersonalAnnotation.coordinate=CLLocationCoordinate2DMake(6.14, 10.7);
[myMap addAnnotation:myPersonalAnnotation];
//...
//add the viewForAnnotation delegate method...
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
//if annotation is the user location, return nil to get default blue-dot...
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
//create purple pin view for all other annotations...
static NSString *reuseId = #"hello";
MKPinAnnotationView *myPersonalView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (myPersonalView == nil)
{
myPersonalView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
myPersonalView.pinColor = MKPinAnnotationColorPurple;
myPersonalView.canShowCallout = YES;
}
else
{
//if re-using view from another annotation, point view to current annotation...
myPersonalView.annotation = annotation;
}
return myPersonalView;
}
Make sure the map view's delegate property is set otherwise the delegate method won't get called.
In code, use myMap.delegate = self; (eg. in viewDidLoad) or make the connection in Interface Builder if myMap is an IBOutlet.
I've created a custom annotation view by subclassing MKAnnotationView. This class also creates a custom callout (info pop-up 'bubble') view which is skinned to match my app.
I also want to be able to reskin the callout bubble for the user location dot, but it seems as though the only control I have over that view is whether it is overridden completely or not, by using the following inside the mapView:viewForAnnotation: method:
if(annotation == self.mapView.userLocation)
{
return nil;
}
But what I really want to do is find out what annotation view MapKit is using for the user location blue dot, and then subclass it so I can skin its callout bubble... Or is there another way? Or just no way at all?
I am not sure this will help you, but you can use the default user location annotation view, then steal the view in mapView:didSelectAnnotationView::
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
if (view == [mapView viewForAnnotation:mapView.userLocation]) {
// do what you want to 'view'
// ...
}
// ...
}
I have used this trick to change the callout title and subtitle, and add an image using leftCalloutAccessoryView. However, I haven't tried totally replacing the callout, so I don't know if it's possible.
You can use
if ([annotation isKindOfClass:[MKUserLocation class]]) { // or if(annotation == self.mapView.userLocation)
MKAnnotationView * annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"MyLocation"];
if (annotationView == nil) {
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"MyLocation"] autorelease];
annotationView.canShowCallout = NO;
annotationView.image = [UIImage imageNamedWithBrand:#"MyLocationPin.png"];
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
I think it is not possible directly, but you can override some methods in runtime with this: http://theocacao.com/document.page/266