Obtenir le rect visible du contenu d’un UIScrollView

Comment puis-je procéder pour 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 quand il n’y a pas de zoom, mais dès que vous autorisez le zoom, il se rompt à 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. si c’est une échelle de zoom 2, la taille du rect sera la moitié de la taille de la vue de défilement, si c’est à l’échelle de zoom 0,5, ce sera le double.)

Ou vous pourriez simplement faire

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

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 correspond à la taille de la vue de contenu. Aussi simplifié un peu le calcul, et ne voyait pas très bien l’utilisation de l’ isless() qui casserait le code chaque fois qu’il serait plus grand.

Vous devez le calculer en utilisant les propriétés contentOffset et contentSize de UIScrollView, comme ceci:

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

Vous pouvez alors le connecter pour un test d’intégrité:

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

Pour prendre en compte le 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, multiplier par 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; } 

Mis à part: j’utilise isless (), isgreater (), isequal () etc. de math.h parce que cela va (probablement) faire la bonne chose en ce qui concerne les résultats de comparaison en virgule flottante «non ordonnés» .


Edit: 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 suis pas sûr si ce comportement est défini, mais presque toutes les sous-classes UIView ont l’origine de leurs bounds définies à (0,0). UIScrollViews, cependant, ont l’origine 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; 

Je ne pense pas qu’un UIScrollView vous donne ce rectangle directement, mais je pense que vous avez tous les éléments nécessaires pour le calculer.

Une combinaison des limites, de contentOffset et de zoomScale est tout ce dont vous avez besoin pour créer le rectangle que vous recherchez.