Tengo un UIImageView
interior UIScrollView
que utilizo para hacer zoom y desplazarme. 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 adhiere 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 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 mínimo de zoom.
- (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)];
}
Respuestas:
¡Tengo una solución muy simple! Todo lo que necesita es actualizar el centro de su subvista (vista de imagen) mientras hace zoom en ScrollViewDelegate. Si la imagen ampliada es más pequeña que la vista de desplazamiento, ajuste subview.center center, el centro es (0,0).
fuente
CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0);
CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentInset.left - scrollView.contentInset.right - scrollView.contentSize.width) * 0.5, 0.0); CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentInset.top - scrollView.contentInset.bottom - scrollView.contentSize.height) * 0.5, 0.0);
zoomToRect:
. El uso delcontentInset
enfoque funciona mejor, si es que necesita esa funcionalidad. Visite petersteinberger.com/blog/2013/how-to-center-uiscrollview para más detalles.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 Swift si alguien la necesita:
fuente
De acuerdo, he estado luchando contra esto durante los últimos dos días, y finalmente he llegado a una solución bastante confiable (hasta ahora ...), pensé que debería compartirlo y ahorrarle un poco de dolor a los demás. :) Si encuentra algún problema con esta solución, ¡grite!
Básicamente he pasado por lo que todos los demás tienen: buscando en StackOverflow, los foros de desarrolladores de Apple, miré el código para three20, ScrollingMadness, ScrollTestSuite, etc. Intenté ampliar el marco UIImageView, jugando con el desplazamiento y / o las inserciones de UIScrollView desde el ViewController, etc. pero nada funcionó muy bien (como todos los demás también lo han descubierto).
Después de dormir, probé un par de ángulos alternativos:
Con este método de subclases UIScrollView, estoy anulando el mutador contentOffset para que no se configure {0,0} cuando la imagen se escala más pequeña que la ventana gráfica, sino que 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 pellizcar con el zoom mínimo lo rompe".
He subido un proyecto de ejemplo a github que usa esta solución, puede encontrarlo aquí: http://github.com/nyoron/NYOBetterZoom
fuente
anOffset.y = -(scrollViewSize.height - zoomViewSize.height) / 2.0
aanOffset.y = (-(scrollViewSize.height - zoomViewSize.height) / 2.0) + 10;
Este código debería funcionar en la mayoría de las versiones de iOS (y ha sido probado para funcionar en 3.1 hacia arriba).
Se basa en el código WWDC de Apple para el photoscoller.
Agregue lo siguiente a su subclase de UIScrollView, y reemplace tileContainerView con la vista que contiene su imagen o mosaicos:
fuente
UIScrollView
enfoque de subclase parece preferible: se invoca cuando la vista se muestra por primera vez + continuamente mientras el zoom está en progreso (mientrasscrollViewDidZoom
que solo se invoca una vez por desplazamiento y después del hecho)Para obtener una solución más adecuada para las vistas de desplazamiento que usan autolayout, use inserciones de contenido de la vista de desplazamiento en lugar de actualizar los marcos de las subvistas de su vista de desplazamiento.
fuente
UIView
que está dentro de laUIScrollview
al mismo centro (view.center = scrollview.center;
) y luego en elscrollViewDidZoom
conjunto de laview.frame.origin
x
yy
de0
nuevo.dispatch_async
cola en la cola principalviewWillAppear
donde llamoscrollViewDidZoom:
a mi vista de desplazamiento principal. Esto hace que la vista aparezca con imágenes centradas.viewDidLayoutSubviews
para asegurarse de que esté configurado correctamente cuando la vista se muestre por primera vez.Actualmente estoy subclasificando
UIScrollView
y anulandosetContentOffset:
para ajustar el desplazamiento segúncontentSize
. Funciona tanto con pellizco como con zoom programático.Además de ser breve y dulce, este código produce un zoom mucho más suave que la solución @Erdemus. Puede verlo en acción en la demostración de RMGallery .
fuente
Pasé un día luchando con este problema y terminé implementando scrollViewDidEndZooming: withView: atScale: como sigue:
Esto garantiza que cuando la imagen sea más pequeña que la pantalla, todavía haya espacio suficiente a su alrededor para que pueda colocarla en el lugar exacto que desee.
(suponiendo que su UIScrollView contiene un UIImageView para contener la imagen)
Esencialmente, lo que esto hace es verificar si el ancho / alto de la vista de la imagen es más pequeño que el ancho / alto de la pantalla, y si es así, crear un recuadro de la mitad del ancho / alto de la pantalla (probablemente podría aumentarlo 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.
fuente
Apple lanzó los videos de la sesión 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 que todo el código esté disponible de forma gratuita.
Tampoco utiliza API privada. No puedo poner ninguno de los códigos aquí debido al acuerdo de no divulgación, pero aquí hay un enlace a la descarga del código de muestra. Probablemente necesitará 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 iTunes WWDC:
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
fuente
Ok, esta solución me está funcionando. Tengo una subclase de
UIScrollView
con una referencia a loUIImageView
que se muestra. Cada vez que seUIScrollView
hace zoom, se ajusta la propiedad contentSize. Es en el setter que escaloUIImageView
apropiadamente y también ajusto su posición central.Cada vez que configuro la imagen, la cambio de
UIScrollView
tamaño. ElUIScrollView
en la vista de desplazamiento también es una clase personalizada que creé.Con estos dos métodos puedo tener una vista que se comporta igual que la aplicación de fotos.
fuente
La forma en que lo hice es agregar una vista adicional a la jerarquía:
Dale
UIView
la misma relación de aspecto que la tuyaUIScrollView
y céntrateUIImageView
en eso.fuente
Sé que algunas respuestas anteriores son correctas, pero solo quiero dar mi respuesta con alguna explicación, los comentarios te harán entender por qué nos gusta esto.
Cuando cargo el scrollView por primera vez, escribo el siguiente código para que sea el centro, tenga en cuenta que configuramos
contentOffset
primero, luegocontentInset
Luego, cuando pellizco vContent, escribo el siguiente código para que sea el centro.
fuente
Si
contentInset
no se necesita para otra cosa, se puede usar para centrar el contenido de scrollview.Ventaja si este enfoque es que aún puede usar
contentLayoutGuide
para colocar contenido dentro de la vista de desplazamientoo simplemente arrastre y suelte el contenido en el Creador de interfaces de Xcode.
fuente
Puede ver la
contentSize
propiedad de UIScrollView (mediante la observación de valores-clave o similar) y ajustar automáticamentecontentInset
cada vez que loscontentSize
cambios sean menores que el tamaño de la vista de desplazamiento.fuente
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
(descrito en developer.apple.com/iphone/library/documentation/UIKit/… ), pero preferiría observarcontentSize
porque de lo contrario terminará descartando la nueva escala de zoom y de todos modos la encontrará en la vista. (A menos que pueda realizar algunas matemáticas increíbles basadas en los tamaños relativos de sus vistas.)Una forma elegante de centrar el contenido
UISCrollView
es esta.Agregue un observador al contenido Tamaño de su
UIScrollView
, por lo que este método se llamará cada vez que cambie el contenido ...Ahora en su método de observador:
Deberías cambiar el
[pointer viewWithTag:100]
. Reemplazar por su vista de contenidoUIView
.imageGallery
orientación hacia el tamaño de su 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
.fuente
Esta es mi solución a ese problema que funciona bastante bien para cualquier tipo de vista dentro de una vista de desplazamiento.
fuente
Hay muchas soluciones aquí, pero me arriesgaría a poner las mías. Es bueno por dos razones: no ensucia la experiencia de zoom, como lo haría al actualizar el marco de vista de imagen en progreso, y también respeta las inserciones de vista de desplazamiento originales (por ejemplo, definidas en xib o storyboard para el manejo elegante de barras de herramientas semitransparentes, etc.) .
Primero, defina un pequeño ayudante:
Para retener inserciones originales, campo definido:
Y en algún lugar de viewDidLoad llénalo:
Para colocar UIImageView en UIScrollView (suponiendo que UIImage se encuentre en loadedImage var):
scrollViewDidZoom: de UIScrollViewDelegate para esa vista de desplazamiento:
Y finalmente, centrándose:
Todavía no probé el cambio de orientación (es decir, la reacción adecuada para cambiar el tamaño de UIScrollView), pero solucionarlo debería ser relativamente fácil.
fuente
Verá que la solución publicada por Erdemus funciona, pero ... Hay algunos casos en los que el método scrollViewDidZoom no se invoca y su imagen está pegada en la esquina superior izquierda. Una solución simple es invocar explícitamente el método cuando inicialmente muestra una imagen, como esta:
En muchos casos, puede invocar este método dos veces, pero esta es una solución más limpia que algunas de las otras respuestas en este tema.
fuente
El ejemplo de Apple Photo Scroller hace exactamente lo que estás buscando. Ponga esto en su subclase UIScrollView y cambie _zoomView para que sea su UIImageView.
Código de muestra de Apple Photo Scroller
fuente
Para que la animación fluya bien, configure
y use esta función (encontrar el centro usando el método en esta respuesta )
Esto crea el efecto de rebote pero no implica ningún movimiento repentino de antemano.
fuente
Solo la respuesta aprobada en forma rápida, pero sin subclasificar con el delegado
fuente
En caso de que su imageView interno tenga un ancho específico inicial (por ejemplo, 300) y solo desee centrar su ancho solo en el zoom más pequeño que su ancho inicial, esto podría ayudarlo también.
fuente
Aquí está la forma actual en que estoy haciendo que esto funcione. Es mejor pero aún no es perfecto. Intenta configurar:
para solucionar el problema con la vista no centrada cuando está en
minZoomScale
.Además, hago lo siguiente para evitar que la imagen se pegue al costado después de alejarse.
fuente
De acuerdo, creo que he encontrado una solución bastante buena para este problema. El truco consiste en reajustar constantemente el
imageView's
marco. Creo que esto funciona mucho mejor que ajustar constantemente elcontentInsets
ocontentOffSets
. Tuve que agregar un poco de código extra para acomodar tanto las imágenes verticales como las horizontales.Aquí está el código:
fuente
Simplemente deshabilite la paginación, para que funcione bien:
fuente
Tuve exactamente el mismo problema. Así es como lo resolví
Este código debería llamarse como resultado de
scrollView:DidScroll:
fuente
Aunque la pregunta es un poco antigua, el problema aún existe. Lo resolví en Xcode 7 al hacer que la restricción de espacio vertical del elemento superior (en este caso, el
topLabel
) a los superViews (elscrollView
) arribaIBOutlet
y luego recalculando su constante cada vez que el contenido cambia dependiendo de la altura de las subvistas de scrollView (topLabel
ybottomLabel
)fuente