37 votes

UIScrollView avec UIImageView centré, comme l'application Photos

Je voudrais avoir une vue de défilement avec une vue de contenu d'image. L'image est en fait une carte qui est beaucoup plus grande que l'écran. La carte devrait être initialement au centre de la vue défilante, comme les photos dans l'application Photos lorsque vous tournez l'iPhone en orientation paysage.

alt text

Je n'ai pas réussi à avoir la carte au centre avec un zoom et un défilement corrects en même temps. Pour autant que l'image de la carte commence en haut de l'écran (en orientation portrait), le code ressemble à quelque chose comme :

- (void)loadView {
    mapView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"map.jpg"]];
    CGFloat mapHeight = MAP_HEIGHT * SCREEN_WIDTH / MAP_WIDTH;
    mapView.frame = CGRectMake(0, 0, SCREEN_WIDTH, mapHeight);
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
    scrollView.delegate = self;
    scrollView.contentSize = mapView.frame.size;
    scrollView.maximumZoomScale = MAP_WIDTH / SCREEN_WIDTH;
    scrollView.minimumZoomScale = 1;
    [scrollView addSubview:mapView];
    self.view = scrollView;
}

Lorsque je déplace le cadre de l'image vers le centre, l'image ne s'agrandit que du haut de son cadre vers le bas. J'ai essayé de jouer avec la transformation de mapView, en changeant dynamiquement le cadre de l'imageView. Rien ne fonctionne pour moi jusqu'à présent.

40voto

JosephH Points 21074

Ce code devrait fonctionner sur la plupart des versions d'iOS (et a été testé pour fonctionner sur les versions 3.1 et supérieures).

Il est basé sur le code Apple WWDC mentionné dans la réponse de Jonah.

Ajoutez le texte ci-dessous à votre sous-classe de UIScrollView, et remplacez tileContainerView par la vue contenant votre image ou vos tuiles :

- (void)layoutSubviews {
    [super layoutSubviews];

    // center the image as it becomes smaller than the size of the screen
    CGSize boundsSize = self.bounds.size;
    CGRect frameToCenter = tileContainerView.frame;

    // center horizontally
    if (frameToCenter.size.width < boundsSize.width)
        frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
    else
        frameToCenter.origin.x = 0;

    // center vertically
    if (frameToCenter.size.height < boundsSize.height)
        frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
    else
        frameToCenter.origin.y = 0;

    tileContainerView.frame = frameToCenter;
}

23voto

Shizam Points 4030

Voici ce que j'envisagerais, la solution dans le sens où elle se comporte exactement comme l'application photo d'Apple. J'avais utilisé des solutions qui utilisaient :

-(void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale

pour recentrer mais je n'aimais pas cette solution parce qu'une fois le zoom effectué, il rebondissait puis "sautait" rapidement au centre, ce qui n'était pas très sexy. Il s'avère que si vous faites exactement la même logique mais dans cette fonction déléguée :

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView

ça commence centré et quand tu dézoomes, ça reste centré :

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView {
CGRect innerFrame = imageView.frame;
CGRect scrollerBounds = pScrollView.bounds;

if ( ( innerFrame.size.width < scrollerBounds.size.width ) || ( innerFrame.size.height < scrollerBounds.size.height ) )
{
    CGFloat tempx = imageView.center.x - ( scrollerBounds.size.width / 2 );
    CGFloat tempy = imageView.center.y - ( scrollerBounds.size.height / 2 );
    CGPoint myScrollViewOffset = CGPointMake( tempx, tempy);

    pScrollView.contentOffset = myScrollViewOffset;

}

UIEdgeInsets anEdgeInset = { 0, 0, 0, 0};
if ( scrollerBounds.size.width > innerFrame.size.width )
{
    anEdgeInset.left = (scrollerBounds.size.width - innerFrame.size.width) / 2;
    anEdgeInset.right = -anEdgeInset.left;  // I don't know why this needs to be negative, but that's what works
}
if ( scrollerBounds.size.height > innerFrame.size.height )
{
    anEdgeInset.top = (scrollerBounds.size.height - innerFrame.size.height) / 2;
    anEdgeInset.bottom = -anEdgeInset.top;  // I don't know why this needs to be negative, but that's what works
}
pScrollView.contentInset = anEdgeInset;
}

Où "imageView" est le UIImageView que vous utilisez.

7voto

Jonah Points 2467

Apple a diffusé les vidéos des sessions de la WWDC 2010 à tous les membres du programme de développement de l'iphone. L'un des sujets abordés est la façon dont ils ont créé l'application photos ! !! Ils ont construit une application très similaire étape par étape et ont rendu tout le code disponible gratuitement.

Il n'utilise pas non plus l'api privée. Je ne peux pas mettre le code ici à cause de l'accord de non-divulgation, mais voici un lien vers le téléchargement de l'échantillon de code. Vous aurez probablement besoin de vous connecter pour y accéder.

http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645

Et voici un lien vers la page WWDC d'iTunes :

http://insideapple.apple.com/redir/cbx-cgi.do?v=2&la=en&lc=&a=kGSol9sgPHP%2BtlWtLp%2BEP%2FnxnZarjWJglPBZRHd3oDbACudP51JNGS8KlsFgxZto9X%2BTsnqSbeUSWX0doe%2Fzv%2FN5XV55%2FomsyfRgFBysOnIVggO%2Fn2p%2BiweDK%2F%2FmsIXj

2voto

Roger Nolan Points 10248

Je soupçonne que vous devez définir le UIScrollView 's contentOffset .

1voto

Martin Ludvik Points 136

J'aimerais que ce soit aussi simple. J'ai fait quelques recherches sur le net et j'ai découvert que ce n'est pas seulement mon problème, mais que beaucoup de gens se débattent avec le même problème non seulement sur l'iPhone, mais aussi sur le bureau Cocoa d'Apple. Voir les liens suivants :

http://www.iphonedevsdk.com/forum/iphone-sdk-development/5740-uiimageview-uiscrollview.html
La solution décrite est basée sur la propriété UIViewContentModeScaleAspectFit de l'image, mais malheureusement elle ne fonctionne pas très bien. L'image est centrée et se développe correctement, mais la zone de rebond semble être beaucoup plus grande que l'image.

Ce type n'a pas eu la réponse non plus :
http://discussions.apple.com/thread.jspa?messageID=8322675

Et enfin, le même problème sur le bureau Cocoa d'Apple :
http://www.cocoadev.com/index.pl?CenteringInsideNSScrollView
Je suppose que la solution fonctionne, mais elle est basée sur le NSClipView, qui n'est pas sur l'iPhone...

Quelqu'un a une solution qui fonctionne sur l'iPhone ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X