Ottenere il rettangolo visibile del contenuto di un UIScrollView
-
22-08-2019 - |
Domanda
Come posso fare per trovare il rect (CGRect) del contenuto di una vista visualizzata che in realtà è visibile sullo schermo.
myScrollView.bounds
Il codice precedente funziona quando non c'è lo zoom, ma non appena si permettono lo zoom, si rompe a scale di zoom diverso da 1.
Per chiarire, io voglio un CGRect che contiene l'area visibile del contenuto della vista di scorrimento, relativa al contenuto. (Es. Se si tratta di una scala di zoom 2, le dimensioni del rettangolo sarà la metà delle dimensioni del vista di scorrimento, se è in scala di zoom 0.5, sarà doppio.)
Soluzione 2
Rispondendo alla mia domanda, per lo più grazie alla risposta di Jim Dovey, che non riusciva a fare 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 del visibleRect dovrebbe essere scrollView.bounds.size
, piuttosto che scrollView.contentSize
, che è la dimensione della vista contenuto. Inoltre semplificato la matematica un po ', e non riusciva a vedere l'uso per il isless()
che rompere il codice ogni volta che è maggiore.
Altri suggerimenti
Oppure si potrebbe semplicemente fare
CGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:zoomedSubview];
Swift
let visibleRect = scrollView.convert(scrollView.bounds, to: zoomedSubview)
Si deve calcolare utilizzando le proprietà contentOffset e contentSize di UIScrollView, in questo modo:
CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.contentSize;
È possibile quindi accedere per sanity-test:
NSLog( @"Visible rect: %@", NSStringFromCGRect(visibleRect) );
Per tenere conto di zoom (se non è già stato fatto dalla proprietà contentSize) si avrebbe bisogno di dividere ogni coordinata dal zoomScale, o per migliorare le prestazioni che ci si moltiplica per 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;
}
A parte: io uso isless (), isgreater (), IsEqual (), ecc da math.h perché questi saranno (presumibilmente) fare la cosa giusta per quanto riguarda in virgola mobile di confronto i risultati 'non ordinati' e altri architecture- strano & meraviglioso specifici casi FP.
Modifica: È necessario utilizzare bounds.size
invece di contentSize
nel calcolo visibleRect.size
versione più breve:
CGRect visibleRect = CGRectApplyAffineTransform(scrollView.bounds, CGAffineTransformMakeScale(1.0 / scrollView.zoomScale, 1.0 / scrollView.zoomScale));
Non sono sicuro se questo viene definito comportamento, ma quasi tutte le sottoclassi UIView avere l'origine della loro bounds
impostato su (0,0). UIScrollViews, tuttavia, hanno il set di origine contentOffset
.
un po 'di soluzione più generale potrebbe essere:
[scrollView convertRect:scrollView.bounds
toView:[scrollView.delegate viewForZoomingInScrollView:scrollView]];
CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.frame.size;
Non credo che un UIScrollView ti dà direttamente che il rettangolo, ma penso di avere tutti gli elementi necessari per calcolarlo.
Una combinazione dei limiti, il contentOffset e la zoomScale dovrebbe essere tutto il necessario per creare il rettangolo che si sta cercando.
Swift 4.0:
La mia risposta adatta risposta di Trenskow per Swift 4.0:
let visible = scrollView.convert(scrollView.bounds, to: subView)
dove scrollView
è la vista della chiocciola, e subView
è la vista all'interno <=> che è stradale e contiene tutti i contenuti all'interno del rotolo.