CALayer after refresh set to others annotationView - ios

For some annotationViews I set some sublayer. First load sublayers match images, but
when I refresh map (clear annotationViews and re-parse info) sublayers not match places and images.
And after each refresh sublayer appears at different positions.
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
SYLocationItem * currentItem;
static NSString *identifier = #"SYLocationItem";
if ([annotation isKindOfClass:[SYLocationItem class]]) {
CATextLayer* subtitle1Text = [CATextLayer layer];
CALayer *sublayer = [CALayer layer];
MKAnnotationView *annotationView = (MKAnnotationView *) [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = NO;
} else {
annotationView.annotation = annotation;
}
currentItem = annotationView.annotation;
SYJabberClient *client = [SYJabberClient sharedClient];
[client retrieveProfileForUserWithEmail:[(SYLocationItem*)annotation email]
withSuccessBlock:^(NSDictionary *dict, NSError *error) {
if (dict) {
UIImage *image = [dict objectForKey:#"imageFile"];
UIImage *displayImage = [UIImage circularScaleNCrop:image
withRect:
CGRectMake(0.0f,0.0f,30.0f,30.0f)];
annotationView.image = displayImage;
if(currentItem.groupSamePlace != nil){
sublayer.backgroundColor = [UIColor redColor].CGColor;
sublayer.cornerRadius = 9.0;
sublayer.frame = CGRectMake(20, -7, 20, 20);
[subtitle1Text setFontSize:12];
[subtitle1Text setFrame:CGRectMake(0, 3, 20, 20)];
NSString *string = [NSString stringWithFormat:#"%#", currentItem.samePlaceCount];
[subtitle1Text setString:string];
[subtitle1Text setAlignmentMode:kCAAlignmentCenter];
[subtitle1Text setForegroundColor:[[UIColor whiteColor] CGColor]];
[sublayer addSublayer:subtitle1Text];
[annotationView.layer addSublayer:sublayer];
}
}
}];
return annotationView;
}
return nil;
}
p.s. Images in correct places.

I found solution.
When refresh just don't use clause:
if (annotationView == nil){
} else {
annotationView.annotation = annotation;
}

Related

MKAnnotationView not working properly

I'm trying to replace the MKAnnotationView image depending on an object value, the code is executed but the images are randomly assigned so they are not matched with the correct values.
- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(EventAnnotation *)annotation{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKAnnotationView *annotationView = [mapview dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if(annotationView)
return annotationView;
else
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:AnnotationIdentifier];
annotationView.canShowCallout = YES;
annotationView.image = [self setImageByType:annotation];
annotationView.draggable = NO;
return annotationView;
}
return nil;
}
setImageByType method:
- (UIImage*)setImageByType:(EventAnnotation *)annotation{
//Set annotation image depending on its type
UIImage *image = [[UIImage alloc]init];
NSString *type = annotation.type;
if ([type isEqualToString:#"event"]) {
image = [UIImage imageNamed:#"geolocalization_events"];
}else if ([type isEqualToString:#"show"]){
image = [UIImage imageNamed:#"geolocalization_shows"];
}else if ([type isEqualToString:#"culture"]){
image = [UIImage imageNamed:#"geolocalization_culture"];
}else if ([type isEqualToString:#"eat"]){
image = [UIImage imageNamed:#"geolocalization_eat"];
}else if ([type isEqualToString:#"drink"]){
image = [UIImage imageNamed:#"geolocalization_drink"];
}else if ([type isEqualToString:#"cybercafe"]){
image = [UIImage imageNamed:#"geolocalization_cybercafe"];
}
UIImage *finalImage = [self imageWithImage:image scaledToSize:CGSizeMake(50, 50)];
return finalImage;
}
resize the image:
- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
//Resize annotation image
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I would say the code is executed faster than the images are assigned to the views. Any ideas?
Option 1
Try changing this line:
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
To this:
NSString* AnnotationIdentifier = annotation.type;
Option 2:
After this line:
MKAnnotationView *annotationView = [mapview dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
Add this line:
annotationView.image = [self setImageByType:annotation];

Display the different images for the annotation in mkMapview

Based on my different enum values, I need to display the different images in my mapview.
How I can do that ? I am new to iOS development. Please anybody help me.
You need to use "ViewForAnnotation" delegate method in your view Controller.
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation
{
if( [annotation isKindOfClass:[Annotation class] ] )
{
static NSString * AnnotationID = #"Annotation";
Annotation * pannotation = (Annotation *)annotation;
//if( pannotation == nil ) return nil;
MKAnnotationView *annotationView = nil;
annotationView = [self.mMapView dequeueReusableAnnotationViewWithIdentifier:AnnotationID];
if( annotationView == nil )
{
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:AnnotationID] autorelease];
}
UIImage * flagImage = nil;
if(Your enum Values)
flagImage = [UIImage imageNamed:#"darkgreendot.png"];
else if(....)
flagImage = [UIImage imageNamed:#"orangedot.png"];
else
flagImage = [UIImage imageNamed:#"bluedot.png"];
CGRect resizeRect;
resizeRect.size = flagImage.size;
resizeRect.origin = (CGPoint){0.0f, 0.0f};
UIGraphicsBeginImageContext(resizeRect.size);
[flagImage drawInRect:resizeRect];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
annotationView.image = resizedImage;
return annotationView;
}
}
Hope this helps you.

I want to plot the MKmapannotation by the photos

Here is my code:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MapLocation *Annotation = annotation;
static NSString *identifier = #"MapLocation";
if ([annotation isKindOfClass:[MapLocation class]]) {
MKPinAnnotationView *annotationViewBus = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
MKPinAnnotationView *annotationViewTaxi = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
MKPinAnnotationView *annotationViewSam = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
MKPinAnnotationView *annotationViewMetro = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
//bus
if (!annotationViewBus ) {
annotationViewBus = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewBus.enabled = YES;
annotationViewBus.canShowCallout = YES;
if (busStatus==YES) {
annotationViewBus.image=[UIImage imageNamed:#"annotationBus.png"];//here we use a nice image instead of the default pins
return annotationViewBus;
}else {
annotationViewBus.annotation = annotation;
}
}
//taxi
if (!annotationViewTaxi ) {
annotationViewTaxi = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewTaxi.enabled = YES;
annotationViewTaxi.canShowCallout = YES;
if (taxiStatus==YES) {
annotationViewTaxi.image=[UIImage imageNamed:#"annotationTaxi.png"];//here we use a nice image instead of the default pins
// return annotationViewTaxi;
}else {
annotationViewTaxi.annotation = annotation;
}
}
//sam
if (!annotationViewSam ) {
annotationViewSam = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewSam.enabled = YES;
annotationViewSam.canShowCallout = YES;
if(samStatus==YES){
annotationViewSam.image=[UIImage imageNamed:#"annotationSam.png"];
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:[Annotation name] forState:UIControlStateNormal];
[rightButton addTarget:self action:#selector(chatButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; //display another view
annotationViewSam.rightCalloutAccessoryView = rightButton;
// return annotationViewSam;
}else {
annotationViewSam.annotation = annotation;
}
}
//metro
if (!annotationViewMetro ) {
annotationViewMetro = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewMetro.enabled = YES;
annotationViewMetro.canShowCallout = YES;
if(metroStatus==YES){
annotationViewMetro.image=[UIImage imageNamed:#"annotationMetro.png"];
}else {
annotationViewMetro.annotation = annotation;
}
//return annotationViewMetro;
}
}
return nil;
}
You have forgotten return (MKAnnotationView *) for each Annotation View type.
Just add return AnnotationView for each type. For example:
//metro
if (!annotationViewMetro ) {
annotationViewMetro = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationViewMetro.enabled = YES;
annotationViewMetro.canShowCallout = YES;
if(metroStatus==YES){
annotationViewMetro.image=[UIImage imageNamed:#"annotationMetro.png"];
}else {
annotationViewMetro.annotation = annotation;
}
just uncomment this line:
return annotationViewMetro;
}

Adding action to MKMapView annotation

I have a MKMapView with a bunch of annotations but I can't add an action to them. I was just creating an MKPointAnnotation, but I couldn't add an action to that. Whenever I click the annotation, nothing happens. Here is how I am setting the annotations -
CLLocationCoordinate2D monteVista;
monteVista.latitude = (double) 37.83029;
monteVista.longitude = (double) -121.98827;
MKPointAnnotation *monteVistaPoint = [[MKPointAnnotation alloc] init];
monteVistaPoint.coordinate = monteVista;
monteVistaPoint.title = #"Monte Vista";
CLLocationCoordinate2D sanRamonValley;
sanRamonValley.latitude = (double) 37.82609;
sanRamonValley.longitude = (double) -122.00603;
MKPointAnnotation *sanRamonValleyPoint = [[MKPointAnnotation alloc] init];
sanRamonValleyPoint.coordinate = sanRamonValley;
sanRamonValleyPoint.title = #"San Ramon Valley";
CLLocationCoordinate2D doughertyValley;
doughertyValley.latitude = (double) 37.76845;
doughertyValley.longitude = (double) -121.90342;
MKPointAnnotation *doughertyValleyPoint = [[MKPointAnnotation alloc] init];
doughertyValleyPoint.coordinate = doughertyValley;
doughertyValleyPoint.title = #"Dougherty Valley";
NSArray *points = [[NSArray alloc] initWithObjects: monteVistaPoint, sanRamonValleyPoint, doughertyValleyPoint, nil];
[self.schoolMap addAnnotations:points];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
NSLog(#"Pin Created");
return annotationView;
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
MKPointAnnotation *testPoint = [[MKPointAnnotation alloc] init];
testPoint = view.annotation;
self.testText.text = testPoint.title;
NSLog(#"Selected");
}
You need to change viewForAnnotation: method in order customize and then just implement openDetail: action method
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation == mapView.userLocation)
{
return nil;
}
static NSString *identifier = #"CustomAnnotation";
MKAnnotationView* annView = nil;
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
annView = (MKAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annView == nil) {
annView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annView.annotation = annotation;
}
UIImage *image = nil;
image = [UIImage imageNamed:#"pin2"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[annView addSubview:imageView];
[annView setFrame:CGRectMake(0, 0, imageView.frame.size.width, imageView.frame.size.height)];
// [annView setBackgroundColor:[UIColor colorWithRed:1 green:0 blue:0 alpha:0.1]];
UIButton*accessory = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[accessory setTag:[(CustomAnnotation*)annotation tag]];
[accessory addTarget:self action:#selector(openDetail:) forControlEvents:UIControlEventTouchUpInside];
[accessory setFrame:CGRectMake(0, 0, 30, 30)];
[annView setRightCalloutAccessoryView:accessory];
}
[annView setEnabled:YES];
[annView setCanShowCallout:YES];
return annView;
}

Refreshing annotations mix photos

First time the view controller load, I download data from web service, then use the details to add annotations.
When I tap the button to download again the data and put in all over again, wrong photos each and every time.
I tried to clear the cache and it doesn't help, I tried a lot of ways.
Any ideas?
EDIT:
- (void)addCustomersToMap
{
marker = nil;
profilePics = [[NSMutableArray alloc] init];
if ([self.usersNearMe isKindOfClass:[NSDictionary class]])
{
NSDictionary *singleUser = (NSDictionary*)self.usersNearMe;
self.usersNearMe = [[NSArray alloc] initWithObjects:singleUser, nil];
}
if ([self.usersNearMe isKindOfClass:[NSArray class]])
{
for (int i = 0; i < self.usersNearMe.count; i++)
{
NSDictionary *dict = self.usersNearMe[i];
float lat = [[dict objectForKey:#"Lat"] floatValue];
float lon = [[dict objectForKey:#"Lon"] floatValue];
NSString *name = [dict objectForKey:#"Name"];
NSString *time = [dict objectForKey:#"Time"];
NSString *picUrl = [dict objectForKey:#"PictureUrl"];
[profilePics addObject:picUrl];
CLLocationCoordinate2D mLoc = CLLocationCoordinate2DMake(lat, lon);
if ([picUrl isEqualToString:#"empty"])
{
marker = [[CustomerMarker alloc] initWithLocation:mLoc title:name andSubtitle:time andUrlString:nil andImagePerson:[UIImage imageNamed:#"user"]];
}
else if ([picUrl isEqualToString:#"system"])
{
marker = [[CustomerMarker alloc] initWithLocation:mLoc title:name andSubtitle:time andUrlString:nil andImagePerson:[UIImage imageNamed:#"police_icon"]];
}
else
{
NSString *completeURL = #"";
completeURL = [completeURL stringByAppendingString:kPROFILE_IMAGE_URL];
completeURL = [completeURL stringByAppendingString:#"/2/"];
completeURL = [completeURL stringByAppendingString:picUrl];
completeURL = [completeURL stringByAppendingString:#".png"];
NSURL *url = [NSURL URLWithString:completeURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *responseData, NSError *error) {
if (responseData) {
NSString *imageName = completeURL.lastPathComponent;
NSString *imagePath = [[self documentsDirectoryPath] stringByAppendingString:imageName];
NSLog(#"imagePath: %#", imagePath);
[responseData writeToFile:imagePath atomically:YES];
marker = [[CustomerMarker alloc] initWithLocation:mLoc title:name andSubtitle:time andUrlString:nil andImagePerson:[UIImage imageWithContentsOfFile:imagePath]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.btnRefreshUsers setImage:[UIImage imageWithContentsOfFile:imagePath] forState:UIControlStateNormal];
[self.mapView viewForAnnotation:marker];
[self.mapView addAnnotation:marker];
});
}
}];
}
}
}
self.btnRefreshUsers.userInteractionEnabled = YES;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
dispatch_async(dispatch_get_main_queue(), ^{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
[self.mapView selectAnnotation:((MKUserLocation*) annotation) animated:YES];
}
});
if ([annotation isKindOfClass:[MKUserLocation class]])
{
((MKUserLocation*) annotation).title = NSLocalizedString(#"current_location", nil);
return nil;
}
if ([annotation isKindOfClass:[CustomerMarker class]])
{
MKAnnotationView *pinView = nil;
static NSString *customerMarkerPinID = #"com.idm.customer";
pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:customerMarkerPinID];
if (!pinView)
{
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:customerMarkerPinID];
}
pinView.canShowCallout = YES;
pinView.backgroundColor = [UIColor clearColor];
CustomerMarker *customerMarker = (CustomerMarker*)annotation;
pinView.image = customerMarker.imagePerson;
CGRect pinViewFrame = CGRectZero;
pinViewFrame.origin.x = pinView.frame.origin.x;
pinViewFrame.origin.y = pinView.frame.origin.y;
pinViewFrame.size.width = 40.0f;
pinViewFrame.size.height = 40.0f;
pinView.frame = pinViewFrame;
////////// Animate Pin Drop //////////
CGRect endFrame = pinView.frame;
pinView.frame = CGRectOffset(pinView.frame, 0, -230);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.45f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
pinView.frame = endFrame;
[UIView commitAnimations];
/* CGRect endFrame = pinView.frame;
pinView.frame = CGRectOffset(pinView.frame, 0, -230);
[UIView animateWithDuration:0.45f delay:0 options:UIViewAnimationOptionShowHideTransitionViews animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
} completion:^(BOOL finished) {
if (finished) {
pinView.frame = endFrame;
}
}]; */
return pinView;
}
return nil;
}
There are two major problems here. First you're reusing a pinView but not setting the attributes according to the annotation that it is trying to draw. You're correct to dequeue a reusable annotationView, but if you reuse one or don't you will always need to set the image to the one you want to draw right now otherwise the pinView's image will be the one that it was previously. e.g.
if ([annotation isKindOfClass:[CustomerMarker class]])
{
MKAnnotationView *pinView = nil;//Create a new handle, don't risk having one global one
static NSString *customerMarkerPinID = #"com.idm.customer";
pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:customerMarkerPinID];
if (!pinView)
{
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:customerMarkerPinID];
//Since all your pinViews can show callouts you only need to set this
//when creating a new one, not when reusing an existing one which will
// already have it set
pinView.canShowCallout = YES;
}
pinView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"map_pic"]];
...
return pinView;
}
//[self.mapView setNeedsDisplay]; <--- Don't do this
return nil;
Secondly you're choosing the image for each pin based on profilePicsCounter which is changed while you're adding the images but the mapView can and will ask for the views in any order it feels like not the order you add them. So you need to respond to viewForAnnotation by calculating the view based on the annotation it gives you. The clue is in the name.
This line:
NSString *urlString = profilePics[profilePicsCounter];
Needs to be something like
MyAnnotationClass *myAnno = (MyAnnotationClass)annotation
NSString *urlString = myAnno.urlString;
Essentially you've got to store the info it needs within the annotation.
Also, the annotations part of removeAllMarkers function can be shortened to one line
[self.mapView removeAnnotations:self.mapView.annotations];
And you're setting the backgroundColor on your pinViews twice

Resources