Comment puis-je trouver le rect (CGRect) du contenu d'une vue affichée qui est réellement visible à l'écran.
myScrollView.bounds
Le code ci-dessus fonctionne lorsqu'il n'y a pas de zoom, mais dès que vous autorisez le zoom, il casse à des échelles de zoom autres que 1.
Pour clarifier, je veux un CGRect qui contient la zone visible du contenu de la vue de défilement, par rapport au contenu. (c.-à-d. s'il s'agit d'une échelle de zoom 2, la taille du rect sera la moitié de la taille de la vue de défilement, si elle est à l'échelle de zoom 0,5, elle sera double.)
Répondre à ma propre question, principalement grâce à la réponse de Jim Dovey, qui n'a pas tout à fait fait l'affaire, mais m'a donné la base de ma réponse:
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 principale différence est que la taille du visibleRect doit être scrollView.bounds.size
, Plutôt que scrollView.contentSize
Qui est la taille de la vue du contenu. Également simplifié un peu les mathématiques, et ne voyait pas vraiment l'utilisation de la isless()
qui briserait le code chaque fois qu'il serait supérieur.
Ou vous pouvez simplement faire
CGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:zoomedSubview];
Swift
let visibleRect = scrollView.convert(scrollView.bounds, to: zoomedSubview)
Vous devez le calculer en utilisant les propriétés contentOffset et contentSize d'UIScrollView, comme ceci:
CGRect visibleRect;
visibleRect.Origin = scrollView.contentOffset;
visibleRect.size = scrollView.contentSize;
Vous pouvez ensuite l'enregistrer pour des tests d'intégrité:
NSLog( @"Visible rect: %@", NSStringFromCGRect(visibleRect) );
Pour tenir compte du zoom (si ce n'est pas déjà fait par la propriété contentSize), vous devez diviser chaque coordonnée par zoomScale, ou pour de meilleures performances, vous devez multiplier par 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;
}
En plus: j'utilise isless (), isgreater (), isequal () etc. de math.h parce que ceux-ci feront (vraisemblablement) la bonne chose en ce qui concerne les résultats de comparaison à virgule flottante 'non ordonnés' et d'autres étranges et merveilleuses spécifiques à l'architecture FP cas.
Modifier: vous devez utiliser bounds.size
Au lieu de contentSize
lors du calcul de visibleRect.size
.
Version plus courte:
CGRect visibleRect = CGRectApplyAffineTransform(scrollView.bounds, CGAffineTransformMakeScale(1.0 / scrollView.zoomScale, 1.0 / scrollView.zoomScale));
Je ne sais pas si c'est un comportement défini, mais presque toutes les sous-classes UIView ont l'origine de leur bounds
définie sur (0,0). Cependant, UIScrollViews a la valeur Origin définie sur contentOffset
.
une solution un peu plus générale serait:
[scrollView convertRect:scrollView.bounds
toView:[scrollView.delegate viewForZoomingInScrollView:scrollView]];
CGRect visibleRect;
visibleRect.Origin = scrollView.contentOffset;
visibleRect.size = scrollView.frame.size;
Swift 4.0:
Ma réponse s'adapte réponse de Trenskow à Swift 4.0:
let visible = scrollView.convert(scrollView.bounds, to: subView)
où scrollView
est la vue du défilement et subView
est la vue à l'intérieur de scrollView
qui est zoomable et contient tout le contenu à l'intérieur du défilement.
Je ne pense pas qu'un UIScrollView vous donne directement ce rectangle, mais je pense que vous avez tous les éléments nécessaires pour le calculer.
Une combinaison des limites, du contentOffset et du zoomScale devrait être tout ce dont vous avez besoin pour créer le rectangle que vous recherchez.