web-dev-qa-db-fra.com

Obtenir le rect visible du contenu d'un UIScrollView

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.)

69

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.

83

Ou vous pouvez simplement faire

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

Swift

let visibleRect = scrollView.convert(scrollView.bounds, to: zoomedSubview)
106
Trenskow

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.

28
Jim Dovey

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.

10
Frank Schmitt

une solution un peu plus générale serait:

 [scrollView convertRect:scrollView.bounds
                             toView:[scrollView.delegate viewForZoomingInScrollView:scrollView]];
5
Nikolay Shubenkov
CGRect visibleRect;
visibleRect.Origin = scrollView.contentOffset;
visibleRect.size = scrollView.frame.size;
2
Bas Dirkse

Swift 4.0:

Ma réponse s'adapte réponse de Trenskow à Swift 4.0:

let visible = scrollView.convert(scrollView.bounds, to: subView)

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.

0
RoberRM

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.

0