objective c - Obtener el rect visible de un contenido de UIScrollView
objective-c iphone (7)
¿Cómo puedo averiguar el rect (CGRect) del contenido de una vista mostrada que es realmente visible en la pantalla?
myScrollView.bounds
El código anterior funciona cuando no hay zoom, pero tan pronto como permite el zoom, se rompe en escalas de zoom que no sean 1.
Para aclarar, quiero un CGRect que contenga el área visible del contenido de la vista de desplazamiento, relativa al contenido. (es decir, si se trata de una escala de zoom 2, el tamaño del recto será la mitad del tamaño de la vista de desplazamiento, si está a una escala de zoom de 0,5, será el doble).
No creo que un UIScrollView te proporcione ese rectángulo directamente, pero creo que tienes todos los elementos necesarios para calcularlo.
Una combinación de los límites, contentOffset y zoomScale debe ser todo lo que necesita para crear el rectángulo que está buscando.
O simplemente podrías hacer
CGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:zoomedSubview];
Respondiendo a mi propia pregunta, en su mayoría gracias a la respuesta de Jim Dovey, que no fue suficiente, pero me dio la base para mi respuesta:
CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.bounds.size;
float theScale = 1.0 / scale;
visibleRect.origin.x *= theScale;
visibleRect.origin.y *= theScale;
visibleRect.size.width *= theScale;
visibleRect.size.height *= theScale;
La principal diferencia es que el tamaño de visibleRect debe ser scrollView.bounds.size
, en lugar de scrollView.contentSize
que es el tamaño de la vista de contenido. También simplificó un poco las matemáticas, y no vio el uso del isless()
que rompería el código cada vez que fuera mayor.
Tienes que calcularlo usando las propiedades contentOffset y contentSize de UIScrollView, así:
CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.contentSize;
A continuación, puede iniciar sesión para la prueba de cordura:
NSLog( @"Visible rect: %@", NSStringFromCGRect(visibleRect) );
Para tener en cuenta el zoom (si esto aún no lo hace la propiedad contentSize) necesitarás dividir cada coordenada con el zoomScale, o para un mejor rendimiento, multiplicar por 1.0 / zoomScale:
CGFloat scale = (CGFloat) 1.0 / scrollView.zoomScale;
if ( isless(scale, 1.0) ) // you need to #include <math.h> for isless()
{
visibleRect.origin.x *= scale;
visibleRect.origin.y *= scale;
visibleRect.size.width *= scale;
visibleRect.size.height *= scale;
}
Aparte: uso isless (), isgreater (), isequal () etc. de math.h porque presumiblemente harán lo correcto con respecto a los resultados de comparación de punto flotante ''no ordenados'' y otros casos de FP específicos de arquitectura extraños y maravillosos .
Editar: debe usar bounds.size
lugar de contentSize
al calcular visibleRect.size
.
Versión más corta:
CGRect visibleRect = CGRectApplyAffineTransform(scrollView.bounds, CGAffineTransformMakeScale(1.0 / scrollView.zoomScale, 1.0 / scrollView.zoomScale));
No estoy seguro de si se trata de un comportamiento definido, pero casi todas las subclases de UIView tienen el origen de sus bounds
establecido en (0,0). UIScrollViews, sin embargo, tiene el origen configurado en contentOffset
.
una solución un poco más general sería:
[scrollView convertRect:scrollView.bounds
toView:[scrollView.delegate viewForZoomingInScrollView:scrollView]];
CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.frame.size;