Question

J'ai un UIScrollView qui a un UIImageView. Je veux montrer des épingles sur cette imageView. Lorsque j'ajoute des épingles en tant que vues secondaires du ImageView, tout est génial, sauf lorsque vous zoomez, la transformation d'échelle se produit également sur les épingles. Je ne veux pas de ce comportement et je veux que mes épingles restent les mêmes.

J'ai donc choisi d'ajouter les punaises à une autre vue qui se trouve au-dessus de ImageView et est également une sous-vue de la <=>. L’idée ici, si vous voulez bien l’imaginer, est d’avoir une couche qui plane sur la carte et ne montrera pas encore les punaises là où je les ai tracées.

La broche ajoutée à la vue des couches ne cale pas si la <=> est mise à l'échelle. Cependant, le problème devient alors que la position des broches ne correspond pas à l'origine x / y d'origine car <=> a subi une transformation d'échelle.

En gros, il s’agit d’une carte personnalisée d’un lieu avec des épingles. J'essaie de faire en sorte que les épingles flottent au-dessus de mon ImageView, sans zoom avant ou arrière, mais je ne me souviens pas où je les ai placées lorsque le zoom est activé.

Certains codes:

scrollView = [[UIScrollView alloc] initWithFrame:viewRect];

scrollView.delegate = self;
scrollView.pagingEnabled = NO;
scrollView.scrollsToTop = NO;
[scrollView setBackgroundColor:[UIColor clearColor]];
scrollView.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView.bounces = YES;
scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;

imageViewMap = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image.png"]];

imageViewMap.userInteractionEnabled = YES;

viewRect = CGRectMake(0,0,imageViewMap.image.size.width,imageViewMap.image.size.height);

//viewRect = CGRectMake(0,0,2976,3928);

[scrollView addSubview:imageViewMap];

[scrollView setContentSize:CGSizeMake(viewRect.size.width, viewRect.size.height)];

iconsView = [[UIView alloc] initWithFrame:imageViewMap.frame];

[scrollView addSubview:iconsView];

Code pour ajouter un code PIN ultérieurement à un événement.

[iconsView addSubview:pinIcon];

Je suis coincé pour essayer de trouver un moyen de faire glisser mes épingles sur la carte sans bouger lorsque l’échelle apparaît.

Était-ce utile?

La solution

J'aime votre idée de conserver toutes les épingles dans une vue dédiée à celles-ci (iconsView), mais j'ai décidé de les ajouter en tant que sous-vues de ce que vous avez appelé imageViewMap.

Importez le fichier QuartzCore.framework dans votre projet.

Appelez votre contrôleur de vue MyViewController.

#import <QuartzCore/QuartzCore.h>
@interface MyViewController : UIViewController <UIScrollViewDelegate>
@property (retain) UIScrollView *scrollView;
@property (retain) UIImageView *imageView;

// et ainsi de suite

@implementation MyViewController

@synthesize scrollView;
@synthesize imageView;

Je présume que vous avez une vue NIP ou un contrôleur de vue appelé DropPinViewController. Si vous utilisez simplement une image, il peut s'agir d'un UIImageView, mais mes pins ont des étiquettes, j'ai donc utilisé un xib. La broche doit pointer vers le bas au centre de xib car nous allons y placer un point d’ancrage.

Dans votre viewDidLoad de votre MyViewController, ajoutez vos vues Pin en tant que sous-vues de imageView. Ajoutez l'imageView en tant que sous-vue à la scrollView. Définissez la taille du contenu de scrollView.

scrollView.delegate = self;

Utilisez ces méthodes de délégué:

- (void)scrollViewDidZoom:(UIScrollView *)aScrollView
{   
    for (UIView *dropPinView in imageView.subviews) {       
    CGRect oldFrame = dropPinView.frame;
    // 0.5 means the anchor is centered on the x axis. 1 means the anchor is at the bottom of the view. If you comment out this line, the pin's center will stay where it is regardless of how much you zoom. I have it so that the bottom of the pin stays fixed. This should help user RomeoF.
   [dropPinView.layer setAnchorPoint:CGPointMake(0.5, 1)];
    dropPinView.frame = oldFrame;
    // When you zoom in on scrollView, it gets a larger zoom scale value.
    // You transform the pin by scaling it by the inverse of this value.
    dropPinView.transform = CGAffineTransformMakeScale(1.0/scrollView.zoomScale, 1.0/scrollView.zoomScale);
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return imageView;
}

Autres conseils

So one thing I have implemented which hasn't solved my issue but I think it's down the right path is from this article.

Anchor a UIView

I have my view hierarchy as follows.

UIScrollView
 - UIImageView (map image)
 - IconsView (layer image to hold icons)

The next step I need to solve is to keep my pins added to IconsView anchored in the same spot when the UIImageView is being zoomed in and out.

I had a for loop that went through all of my pins which are Subviews of IconsView and updated their Origin X and Y. This was in the UIScrollView delegates's scrollViewDidScroll method.

The problem was this technique has horrible performance on the device as when there are a lot of pins on the map there is too much processing that needs to happen.

A few recommendations:

1) You will notice in the Google Maps application that it limits the number of pins that it tries to display by default. It will only display the results closest the the center point even if there are more possible matches.

2) You could briefly hide the pins during any scroll or pinch action so that the interface remains responsive and redraw them the moment the image view stops moving.

3) If you must display a large number of pins and animate them, you might also look into using CABasicAnimations to animate the pins and the backdrop at the same time, transforming the pins position using the same math that transforms the backdrops scale. This might smooth the display by spreading animations more smoothly and running them at a fairly low level, but introduces other challenges and limitations.

http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Animation_Types_Timing/Articles/PropertyAnimations.html#//apple_ref/doc/uid/TP40006672-SW1

Barney

I have the same problem and I find the idea of manually correcting the pin's location not very pretty. Then, I rather draw my pins onto the view returned in the delegate function viewForZoomingInScrollView: and update the subview (markers) size after zooming has finished.

However, it nags me that this is possible in the Google Maps App, but I can't recreate it.

One more thing: Can anyone explain me the behaviour exhibitet when I add subviews to the UIScrollView that are not the 'viewForZoomingInScrollView'..? For example:

UIImageView* marker = [[UIImageView alloc] initWithImage: myMarkerImage];
[marker setCenter: CGPointMake(250,150)];
[myScrollView addSubview: marker];

This seems to work fine for the initial view and when panning. When zooming, those subviews are not resized, which is actually what we are aiming for, but the problem is that the UIView frame origin is moved across the scroll view in some rather weird way. It appears that if one zooms in, the marker.frame.size.origin is always moving towards the upper left corner (superview's (0,0)), creating the impression that we are actually zooming out. This is also weird, because the "zoom center" should always be at the center of the screen, no? Well, I don't get it for now.

bump. ;)

Thanks to David Braun. Your code works except for one line that I had to comment out. My project involved having a UIScrollView, then a UIImageView on top that shows a map, then lastly, pins (buttons) that the code positions after sensing a double tap gesture. Your code helped me account for the zoom scale. The limitation though was that when I pinch to zoom, each pin does not "stick" to the specific part of the drawing where I double tapped. I stumbled on the solution when I commented out this line:

//[dropPinView.layer setAnchorPoint:CGPointMake(0.5, 1)];

I don't have the complete understanding but my code now works! I hope others will benefit from my experience. Thanks David!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top