tutorial inside doesn ios objective-c cocoa-touch uiscrollview uiimageview

ios - inside - Centrar el contenido de UIScrollView cuando es más pequeño



uiscrollview ios (24)

Tengo un UIImageView dentro de UIScrollView que uso para acercar y desplazar. Si la imagen / contenido de la vista de desplazamiento es más grande que la vista de desplazamiento, todo funciona bien. Sin embargo, cuando la imagen se vuelve más pequeña que la vista de desplazamiento, se pega a la esquina superior izquierda de la vista de desplazamiento. Me gustaría mantenerlo centrado, como la aplicación Fotos.

¿Alguna idea o ejemplo sobre cómo mantener el contenido de UIScrollView centrado cuando es más pequeño?

Estoy trabajando con iPhone 3.0.

El siguiente código casi funciona. La imagen vuelve a la esquina superior izquierda si la pellizco después de alcanzar el nivel de zoom mínimo.

- (void)loadView { [super loadView]; // set up main scroll view imageScrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]]; [imageScrollView setBackgroundColor:[UIColor blackColor]]; [imageScrollView setDelegate:self]; [imageScrollView setBouncesZoom:YES]; [[self view] addSubview:imageScrollView]; UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"WeCanDoIt.png"]]; [imageView setTag:ZOOM_VIEW_TAG]; [imageScrollView setContentSize:[imageView frame].size]; [imageScrollView addSubview:imageView]; CGSize imageSize = imageView.image.size; [imageView release]; CGSize maxSize = imageScrollView.frame.size; CGFloat widthRatio = maxSize.width / imageSize.width; CGFloat heightRatio = maxSize.height / imageSize.height; CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio; [imageScrollView setMinimumZoomScale:initialZoom]; [imageScrollView setZoomScale:1]; float topInset = (maxSize.height - imageSize.height) / 2.0; float sideInset = (maxSize.width - imageSize.width) / 2.0; if (topInset < 0.0) topInset = 0.0; if (sideInset < 0.0) sideInset = 0.0; [imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)]; } - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return [imageScrollView viewWithTag:ZOOM_VIEW_TAG]; } /************************************** NOTE **************************************/ /* The following delegate method works around a known bug in zoomToRect:animated: */ /* In the next release after 3.0 this workaround will no longer be necessary */ /**********************************************************************************/ - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale { [scrollView setZoomScale:scale+0.01 animated:NO]; [scrollView setZoomScale:scale animated:NO]; // END Bug workaround CGSize maxSize = imageScrollView.frame.size; CGSize viewSize = view.frame.size; float topInset = (maxSize.height - viewSize.height) / 2.0; float sideInset = (maxSize.width - viewSize.width) / 2.0; if (topInset < 0.0) topInset = 0.0; if (sideInset < 0.0) sideInset = 0.0; [imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)]; }


¡Tengo una solución muy simple! Todo lo que necesita es actualizar el centro de su subvista (visualización de la imagen) mientras hace zoom en ScrollViewDelegate. Si la imagen ampliada es más pequeña que la vista de desplazamiento, entonces ajuste el centro de la subvista.centro else es (0,0).

- (void)scrollViewDidZoom:(UIScrollView *)scrollView { UIView *subView = [scrollView.subviews objectAtIndex:0]; CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0); CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5, 0.0); subView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, scrollView.contentSize.height * 0.5 + offsetY); }


Actualmente estoy subclasificando UIScrollView y reemplazando setContentOffset: para ajustar el desplazamiento en función de contentSize . Funciona tanto con pellizco como con zoom programático.

@implementation HPCenteringScrollView - (void)setContentOffset:(CGPoint)contentOffset { const CGSize contentSize = self.contentSize; const CGSize scrollViewSize = self.bounds.size; if (contentSize.width < scrollViewSize.width) { contentOffset.x = -(scrollViewSize.width - contentSize.width) / 2.0; } if (contentSize.height < scrollViewSize.height) { contentOffset.y = -(scrollViewSize.height - contentSize.height) / 2.0; } [super setContentOffset:contentOffset]; } @end

Además de ser corto y dulce, este código produce un zoom mucho más suave que la solución @Erdemus. Puedes verlo en acción en la demo de RMGallery .


Apple ha lanzado los videos de la sesión de la WWDC 2010 a todos los miembros del programa para desarrolladores de iphone. ¡Uno de los temas discutidos es cómo crearon la aplicación de fotos! Construyen una aplicación muy similar paso a paso y han hecho todo el código disponible de forma gratuita.

No usa una API privada tampoco. No puedo poner aquí ningún código debido al acuerdo de no divulgación, pero aquí hay un enlace a la descarga del código de muestra. Probablemente necesites iniciar sesión para obtener acceso.

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

Y, aquí hay un enlace a la página WWDC de 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


Aquí hay muchas soluciones, pero me arriesgaría a poner las mías. Es bueno por dos razones: no estropea la experiencia de acercamiento, como lo haría actualizar el marco de vista de imagen en progreso, y también respeta las inserciones originales de vista de desplazamiento (digamos, definidas en xib o guiones gráficos para un manejo elegante de barras de herramientas semitransparentes, etc.) .

Primero, define un pequeño ayudante:

CGSize CGSizeWithAspectFit(CGSize containerSize, CGSize contentSize) { CGFloat containerAspect = containerSize.width / containerSize.height, contentAspect = contentSize.width / contentSize.height; CGFloat scale = containerAspect > contentAspect ? containerSize.height / contentSize.height : containerSize.width / contentSize.width; return CGSizeMake(contentSize.width * scale, contentSize.height * scale); }

Para retener inserciones originales, campo definido:

UIEdgeInsets originalScrollViewInsets;

Y en algún lugar en viewDidLoad llenalo:

originalScrollViewInsets = self.scrollView.contentInset;

Para colocar UIImageView en UIScrollView (suponiendo que UIImage esté en loadImage var):

CGSize containerSize = self.scrollView.bounds.size; containerSize.height -= originalScrollViewInsets.top + originalScrollViewInsets.bottom; containerSize.width -= originalScrollViewInsets.left + originalScrollViewInsets.right; CGSize contentSize = CGSizeWithAspectFit(containerSize, loadedImage.size); UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRect) { CGPointZero, contentSize }]; imageView.autoresizingMask = UIViewAutoresizingNone; imageView.contentMode = UIViewContentModeScaleAspectFit; imageView.image = loadedImage; [self.scrollView addSubview:imageView]; self.scrollView.contentSize = contentSize; [self centerImageViewInScrollView];

scrollViewDidZoom: de UIScrollViewDelegate para esa vista de desplazamiento:

- (void)scrollViewDidZoom:(UIScrollView *)scrollView { if (scrollView == self.scrollView) { [self centerImageViewInScrollView]; } }

Finalmente, centrándose en sí mismo:

- (void)centerImageViewInScrollView { CGFloat excessiveWidth = MAX(0.0, self.scrollView.bounds.size.width - self.scrollView.contentSize.width), excessiveHeight = MAX(0.0, self.scrollView.bounds.size.height - self.scrollView.contentSize.height), insetX = excessiveWidth / 2.0, insetY = excessiveHeight / 2.0; self.scrollView.contentInset = UIEdgeInsetsMake( MAX(insetY, originalScrollViewInsets.top), MAX(insetX, originalScrollViewInsets.left), MAX(insetY, originalScrollViewInsets.bottom), MAX(insetX, originalScrollViewInsets.right) ); }

No probé el cambio de orientación todavía (es decir, la reacción adecuada para cambiar el tamaño de UIScrollView), pero la solución para eso debería ser relativamente fácil.


De acuerdo, he estado luchando con esto durante los últimos dos días y finalmente habiendo llegado a una solución bastante confiable (hasta ahora ...), pensé que debería compartirla y ahorrarle a otros un poco de dolor. :) Si encuentras un problema con esta solución, por favor grita!

Básicamente he pasado por lo que todos los demás: buscando en , los foros de desarrolladores de Apple, miré el código para tres20, ScrollingMadness, ScrollTestSuite, etc. He intentado ampliar el marco UIImageView, jugando con el desplazamiento y / o las inserciones de UIScrollView desde ViewController, etc. pero nada funcionó de maravilla (ya que todos los demás también se han enterado).

Después de dormir en él, intenté un par de ángulos alternativos:

  1. Subclasificando el UIImageView para que altere su propio tamaño dinámicamente, esto no funcionó para nada.
  2. Subclasificando el UIScrollView para que modifique su propio contentOffset dinámicamente, este es el que parece ser el ganador para mí.

Con este método de subclasificación UIScrollView anulo el mutador contentOffset para que no se establezca {0,0} cuando la imagen se escala más pequeña que la ventana gráfica; en su lugar, se establece el desplazamiento de modo que la imagen se mantenga centrada en la ventana gráfica. Hasta ahora, siempre parece funcionar. Lo he comprobado con imágenes anchas, altas, pequeñas y grandes y no tiene el problema "funciona, pero pellizca al mínimo el zoom lo rompe".

He subido un proyecto de ejemplo a github que usa esta solución, puedes encontrarlo aquí: http://github.com/nyoron/NYOBetterZoom


Descubrirá que la solución publicada por Erdemus funciona, pero ... Hay algunos casos en los que el método scrollViewDidZoom no se invoca y la imagen se pega a la esquina superior izquierda. Una solución simple es invocar explícitamente el método cuando inicialmente se muestra una imagen, como esta:

[self scrollViewDidZoom: scrollView];

En muchos casos, puede estar invocando este método dos veces, pero esta es una solución más limpia que algunas de las otras respuestas en este tema.


El ejemplo de Apple Photo Scroller hace exactamente lo que estás buscando. Pon esto en tu subclase UIScrollView y cambia _zoomView para que sea tu UIImageView.

-(void)layoutSubviews{ [super layoutSubviews]; // center the zoom view as it becomes smaller than the size of the screen CGSize boundsSize = self.bounds.size; CGRect frameToCenter = self.imageView.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; } self.imageView.frame = frameToCenter; }

Código de ejemplo de Apple''s Photo Scroller


En caso de que tu imageView interno tenga un ancho específico inicial (por ejemplo, 300) y solo quieras centrar su ancho solo en un zoom más pequeño que su ancho inicial, esto también podría ayudarte.

func scrollViewDidZoom(scrollView: UIScrollView){ if imageView.frame.size.width < 300{ imageView.center.x = self.view.frame.width/2 } }


Esta es la forma actual en que estoy haciendo que esto funcione. Es mejor, pero aún no es perfecto. Intenta configurar:

myScrollView.bouncesZoom = YES;

para solucionar el problema con la vista no centrada cuando en minZoomScale .

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGSize screenSize = [[self view] bounds].size;//[[UIScreen mainScreen] bounds].size;// CGSize photoSize = [yourImage size]; CGFloat topInset = (screenSize.height - photoSize.height * [myScrollView zoomScale]) / 2.0; CGFloat sideInset = (screenSize.width - photoSize.width * [myScrollView zoomScale]) / 2.0; if (topInset < 0.0) { topInset = 0.0; } if (sideInset < 0.0) { sideInset = 0.0; } [myScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)]; ApplicationDelegate *appDelegate = (ApplicationDelegate *)[[UIApplication sharedApplication] delegate]; CGFloat scrollViewHeight; //Used later to calculate the height of the scrollView if (appDelegate.navigationController.navigationBar.hidden == YES) //If the NavBar is Hidden, set scrollViewHeight to 480 { scrollViewHeight = 480; } if (appDelegate.navigationController.navigationBar.hidden == NO) //If the NavBar not Hidden, set scrollViewHeight to 360 { scrollViewHeight = 368; } imageView.frame = CGRectMake(0, 0, CGImageGetWidth(yourImage)* [myScrollView zoomScale], CGImageGetHeight(yourImage)* [myScrollView zoomScale]); [imageView setContentMode:UIViewContentModeCenter]; }

Also, I do the following to prevent the image from sticking a the side after zooming out.

- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale { myScrollView.frame = CGRectMake(0, 0, 320, 420); //put the correct parameters for your scroll view width and height above }


Esta es mi solución a ese problema que funciona bastante bien para cualquier tipo de vista dentro de una vista de desplazamiento.

-(void)scrollViewDidZoom:(__unused UIScrollView *)scrollView { CGFloat top; CGFloat left; CGFloat bottom; CGFloat right; if (_scrollView.contentSize.width < scrollView.bounds.size.width) { DDLogInfo(@"contentSize %@",NSStringFromCGSize(_scrollView.contentSize)); CGFloat width = (_scrollView.bounds.size.width-_scrollView.contentSize.width)/2.0; left = width; right = width; }else { left = kInset; right = kInset; } if (_scrollView.contentSize.height < scrollView.bounds.size.height) { CGFloat height = (_scrollView.bounds.size.height-_scrollView.contentSize.height)/2.0; top = height; bottom = height; }else { top = kInset; right = kInset; } _scrollView.contentInset = UIEdgeInsetsMake(top, left, bottom, right); if ([self.tiledScrollViewDelegate respondsToSelector:@selector(tiledScrollViewDidZoom:)]) { [self.tiledScrollViewDelegate tiledScrollViewDidZoom:self]; } }


Este código debería funcionar en la mayoría de las versiones de iOS (y se ha probado que funciona en 3.1 hacia arriba).

Se basa en el código de Apple WWDC para el photoscoller.

Agregue lo siguiente a su subclase de UIScrollView y reemplace tileContainerView con la vista que contiene su imagen o mosaicos:

- (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; }


La forma en que lo hice es agregar una vista adicional a la jerarquía:

UIScrollView -> UIView -> UIImageView

Dale a tu UIView la misma relación de aspecto que tu UIScrollView , y centra tu UIImageView en eso.


Ok, esta solución está funcionando para mí. Tengo una subclase de UIScrollView con una referencia al UIImageView que se muestra. Cada vez que UIScrollView acerca, se ajusta la propiedad contentSize. Es en el setter que UIImageView el UIImageView apropiadamente y también ajusto su posición central.

-(void) setContentSize:(CGSize) size{ CGSize lSelfSize = self.frame.size; CGPoint mid; if(self.zoomScale >= self.minimumZoomScale){ CGSize lImageSize = cachedImageView.initialSize; float newHeight = lImageSize.height * self.zoomScale; if (newHeight < lSelfSize.height ) { newHeight = lSelfSize.height; } size.height = newHeight; float newWidth = lImageSize.width * self.zoomScale; if (newWidth < lSelfSize.width ) { newWidth = lSelfSize.width; } size.width = newWidth; mid = CGPointMake(size.width/2, size.height/2); } else { mid = CGPointMake(lSelfSize.width/2, lSelfSize.height/2); } cachedImageView.center = mid; [super setContentSize:size]; [self printLocations]; NSLog(@"zoom %f setting size %f x %f",self.zoomScale,size.width,size.height); }

En horas extras configuro la imagen en UIScrollView Le cambio el tamaño. UIScrollView en la vista de desplazamiento también es una clase personalizada que creé.

-(void) resetSize{ if (!scrollView){//scroll view is view containing imageview return; } CGSize lSize = scrollView.frame.size; CGSize lSelfSize = self.image.size; float lWidth = lSize.width/lSelfSize.width; float lHeight = lSize.height/lSelfSize.height; // choose minimum scale so image width fits screen float factor = (lWidth<lHeight)?lWidth:lHeight; initialSize.height = lSelfSize.height * factor; initialSize.width = lSelfSize.width * factor; [scrollView setContentSize:lSize]; [scrollView setContentOffset:CGPointZero]; scrollView.userInteractionEnabled = YES; }

Con estos dos métodos, puedo tener una vista que se comporta como la aplicación de fotos.


Para que la animación fluya bien, configure

self.scrollview.bouncesZoom = NO;

y use esta función (encontrar el centro usando el método en esta respuesta )

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { [UIView animateWithDuration:0.2 animations:^{ float offsetX = MAX((scrollView.bounds.size.width-scrollView.contentSize.width)/2, 0); float offsetY = MAX((scrollView.bounds.size.height-scrollView.contentSize.height)/2, 0); self.imageCoverView.center = CGPointMake(scrollView.contentSize.width*0.5+offsetX, scrollView.contentSize.height*0.5+offsetY); }]; }

Esto crea el efecto de rebote pero no implica ningún movimiento repentino de antemano.


Para una solución más adecuada para las vistas de desplazamiento que usan el diseño automático, use las inserciones de contenido de la vista de desplazamiento en lugar de actualizar los marcos de las subvistas de la vista de desplazamiento.

- (void)scrollViewDidZoom:(UIScrollView *)scrollView { CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0); CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5, 0.0); self.scrollView.contentInset = UIEdgeInsetsMake(offsetY, offsetX, 0.f, 0.f); }


Pasé un día luchando con este problema y terminé implementando scrollViewDidEndZooming: withView: atScale: de la siguiente manera:

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale { CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width; CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height; CGFloat viewWidth = view.frame.size.width; CGFloat viewHeight = view.frame.size.height; CGFloat x = 0; CGFloat y = 0; if(viewWidth < screenWidth) { x = screenWidth / 2; } if(viewHeight < screenHeight) { y = screenHeight / 2 ; } self.scrollView.contentInset = UIEdgeInsetsMake(y, x, y, x); }

Esto garantiza que cuando la imagen sea más pequeña que la pantalla, aún haya suficiente espacio alrededor para que pueda colocarla en el lugar exacto que desee.

(suponiendo que su UIScrollView contiene un UIImageView para contener la imagen)

Básicamente, lo que hace es verificar si el ancho / alto de su vista de imagen es más pequeño que el ancho / alto de la pantalla y, de ser así, crear un recuadro de la mitad del ancho / alto de la pantalla (probablemente podría ampliarlo si desea que la imagen salir de los límites de la pantalla).

Tenga en cuenta que dado que este es un método UIScrollViewDelegate , no olvide agregarlo a la declaración de su controlador de vista, para evitar problemas de compilación.


Puede ver la propiedad contentSize de UIScrollView (usando la observación de valor-clave o similar) y ajustar automáticamente el contentInset siempre que el tamaño del contentSize cambie para que sea menor que el tamaño de la vista de desplazamiento.


Simplemente la respuesta aprobada en breve, pero sin subclases usando el delegado

func centerScrollViewContents(scrollView: UIScrollView) { let contentSize = scrollView.contentSize let scrollViewSize = scrollView.frame.size; var contentOffset = scrollView.contentOffset; if (contentSize.width < scrollViewSize.width) { contentOffset.x = -(scrollViewSize.width - contentSize.width) / 2.0 } if (contentSize.height < scrollViewSize.height) { contentOffset.y = -(scrollViewSize.height - contentSize.height) / 2.0 } scrollView.setContentOffset(contentOffset, animated: false) } // UIScrollViewDelegate func scrollViewDidZoom(scrollView: UIScrollView) { centerScrollViewContents(scrollView) }


Tuve exactamente el mismo problema. Here is how I solved

This code should get called as the result of scrollView:DidScroll:

CGFloat imageHeight = self.imageView.frame.size.width * self.imageView.image.size.height / self.imageView.image.size.width; BOOL imageSmallerThanContent = (imageHeight < self.scrollview.frame.size.height) ? YES : NO; CGFloat topOffset = (self.imageView.frame.size.height - imageHeight) / 2; // If image is not large enough setup content offset in a way that image is centered and not vertically scrollable if (imageSmallerThanContent) { topOffset = topOffset - ((self.scrollview.frame.size.height - imageHeight)/2); } self.scrollview.contentInset = UIEdgeInsetsMake(topOffset * -1, 0, topOffset * -1, 0);


Una manera elegante de centrar el contenido de UISCrollView es esto.

Agregue un observador al contenido Tamaño de su UIScrollView , por lo que este método se llamará cada vez que cambie el contenido ...

[myScrollView addObserver:delegate forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];

Ahora en tu método de observación:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { // Correct Object Class. UIScrollView *pointer = object; // Calculate Center. CGFloat topCorrect = ([pointer bounds].size.height - [pointer viewWithTag:100].bounds.size.height * [pointer zoomScale]) / 2.0 ; topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect ); topCorrect = topCorrect - ( pointer.frame.origin.y - imageGallery.frame.origin.y ); // Apply Correct Center. pointer.center = CGPointMake(pointer.center.x, pointer.center.y + topCorrect ); }

  • Debería cambiar el [pointer viewWithTag:100] . Reemplazar por su contenido ver UIView .

    • También cambie imageGallery apuntando a su tamaño de ventana.

Esto corregirá el centro del contenido cada vez que cambie su tamaño.

NOTA: La única forma en que este contenido no funciona muy bien es con la funcionalidad de zoom estándar de UIScrollView .


Although the question is a bit old yet the problem still exists. I solved it in Xcode 7 by making the vertical space constraint of the uppermost item (in this case the topLabel ) to the superViews (the scrollView ) top an IBOutlet and then recalculating its constant every time the content changes depending on the height of the scrollView''s subviews ( topLabel and bottomLabel ).

class MyViewController: UIViewController { @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var topLabel: UILabel! @IBOutlet weak var bottomLabel: UILabel! @IBOutlet weak var toTopConstraint: NSLayoutConstraint! override func viewDidLayoutSubviews() { let heightOfScrollViewContents = (topLabel.frame.origin.y + topLabel.frame.size.height - bottomLabel.frame.origin.y) // In my case abs() delivers the perfect result, but you could also check if the heightOfScrollViewContents is greater than 0. toTopConstraint.constant = abs((scrollView.frame.height - heightOfScrollViewContents) / 2) } func refreshContents() { // Set the label''s text … self.view.layoutIfNeeded() } }


Just disable the pagination, so it''ll work fine:

scrollview.pagingEnabled = NO;


La respuesta de @ EvelynCordner fue la que mejor funcionó en mi aplicación. Mucho menos código que las otras opciones también.

Aquí está la versión de Swift si alguien lo necesita:

func scrollViewDidZoom(scrollView: UIScrollView) { let offsetX = max((scrollView.bounds.width - scrollView.contentSize.width) * 0.5, 0) let offsetY = max((scrollView.bounds.height - scrollView.contentSize.height) * 0.5, 0) self.scrollView.contentInset = UIEdgeInsetsMake(offsetY, offsetX, 0, 0) }


Okay, I think I''ve found a pretty good solution to this problem. The trick is to constantly readjust the imageView''s frame. I find this works much better than constantly adjusting the contentInsets or contentOffSets . I had to add a bit of extra code to accommodate both portrait and landscape images.

Aquí está el código:

- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale { CGSize screenSize = [[self view] bounds].size; if (myScrollView.zoomScale <= initialZoom +0.01) //This resolves a problem with the code not working correctly when zooming all the way out. { imageView.frame = [[self view] bounds]; [myScrollView setZoomScale:myScrollView.zoomScale +0.01]; } if (myScrollView.zoomScale > initialZoom) { if (CGImageGetWidth(temporaryImage.CGImage) > CGImageGetHeight(temporaryImage.CGImage)) //If the image is wider than tall, do the following... { if (screenSize.height >= CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the height of the screen is greater than the zoomed height of the image do the following... { imageView.frame = CGRectMake(0, 0, 320*(myScrollView.zoomScale), 368); } if (screenSize.height < CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the height of the screen is less than the zoomed height of the image do the following... { imageView.frame = CGRectMake(0, 0, 320*(myScrollView.zoomScale), CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]); } } if (CGImageGetWidth(temporaryImage.CGImage) < CGImageGetHeight(temporaryImage.CGImage)) //If the image is taller than wide, do the following... { CGFloat portraitHeight; if (CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale] < 368) { portraitHeight = 368;} else {portraitHeight = CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale];} if (screenSize.width >= CGImageGetWidth(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the width of the screen is greater than the zoomed width of the image do the following... { imageView.frame = CGRectMake(0, 0, 320, portraitHeight); } if (screenSize.width < CGImageGetWidth (temporaryImage.CGImage) * [myScrollView zoomScale]) //If the width of the screen is less than the zoomed width of the image do the following... { imageView.frame = CGRectMake(0, 0, CGImageGetWidth(temporaryImage.CGImage) * [myScrollView zoomScale], portraitHeight); } } [myScrollView setZoomScale:myScrollView.zoomScale -0.01]; }