Ottenere il rect visibile di un contenuto di UIScrollView

Come posso andare a scoprire il giusto (CGRect) del contenuto di una vista visualizzata che è effettivamente visibile sullo schermo.

myScrollView.bounds 

Il codice sopra funziona quando non c’è lo zoom, ma non appena lo zoom lo consente, si rompe con una scala dello zoom diversa da 1.

Per chiarire, voglio un CGRect che contenga l’area visibile del contenuto della vista di scorrimento, relativamente al contenuto. (ad esempio se si tratta di una scala di zoom 2, la dimensione del rect sarà metà della dimensione della vista di scorrimento, se è a scala 0.5, sarà doppia).

O potresti semplicemente farlo

 CGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:zoomedSubview]; 

Rispondendo alla mia domanda, soprattutto grazie alla risposta di Jim Dovey, che non ha fatto proprio il trucco, ma mi ha dato la base per la mia risposta:

 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 differenza principale è che la dimensione di visibleRect dovrebbe essere scrollView.bounds.size , piuttosto che scrollView.contentSize che è la dimensione della visualizzazione del contenuto. Semplificato anche un po ‘la matematica, e non ho visto l’uso per isless() che avrebbe infranto il codice ogni volta che è più grande.

Devi calcolarlo usando le proprietà contentOffset e contentSize di UIScrollView, in questo modo:

 CGRect visibleRect; visibleRect.origin = scrollView.contentOffset; visibleRect.size = scrollView.contentSize; 

Puoi quindi loggarlo per test di sanità:

 NSLog( @"Visible rect: %@", NSStringFromCGRect(visibleRect) ); 

Per tenere conto dello zoom (se questo non è già stato fatto dalla proprietà contentSize) dovresti dividere ogni coordinata con lo zoomScale, o per ottenere prestazioni migliori moltiplicandole per 1.0 / zoomScale:

 CGFloat scale = (CGFloat) 1.0 / scrollView.zoomScale; if ( isless(scale, 1.0) ) // you need to #include  for isless() { visibleRect.origin.x *= scale; visibleRect.origin.y *= scale; visibleRect.size.width *= scale; visibleRect.size.height *= scale; } 

A parte: io uso isless (), isgreater (), isequal () ecc. Da math.h perché questi (presumibilmente) fanno la cosa giusta per quanto riguarda i risultati di confronto in virgola mobile “non ordinati” e altri casi di FP specifici per architettura particolari e meravigliosi .


Modifica: per il bounds.size di contentSize è necessario utilizzare bounds.size anziché visibleRect.size .

Versione più breve:

 CGRect visibleRect = CGRectApplyAffineTransform(scrollView.bounds, CGAffineTransformMakeScale(1.0 / scrollView.zoomScale, 1.0 / scrollView.zoomScale)); 

Non sono sicuro che questo comportamento sia definito, ma quasi tutte le sottoclassi di UIView hanno l’origine dei loro bounds impostati su (0,0). Le viste UIScroll, tuttavia, hanno l’origine impostata su contentOffset .

una soluzione un po ‘più generale sarebbe:

  [scrollView convertRect:scrollView.bounds toView:[scrollView.delegate viewForZoomingInScrollView:scrollView]]; 
 CGRect visibleRect; visibleRect.origin = scrollView.contentOffset; visibleRect.size = scrollView.frame.size; 

Non penso che un UIScrollView ti dia direttamente quel rettangolo, ma penso che tu abbia tutti gli elementi necessari per calcolarlo.

Una combinazione di limiti, contentOffset e zoomScale dovrebbe essere tutto ciò che serve per creare il rettangolo che stai cercando.