J'ai un UIImageView
intérieur UIScrollView
que j'utilise pour le zoom et le défilement. Si l'image / le contenu de la vue de défilement est plus grand que la vue de défilement, tout fonctionne bien. Cependant, lorsque l'image devient plus petite que la vue de défilement, elle reste dans le coin supérieur gauche de la vue de défilement. Je souhaite rester centré, comme l'application Photos.
Des idées ou des exemples pour garder le contenu du UIScrollView
centré quand il est plus petit?
Je travaille avec l'iPhone 3.0.
Le code suivant fonctionne presque. L'image revient dans le coin supérieur gauche si je la pince après avoir atteint le niveau de zoom minimum.
- (void)loadView {
[super loadView];
// set up main scroll view
imageScrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]];
[imageScrollView setBackgroundColor:[UIColor blackColor]];
[imageScrollView setDelegate:self];
[imageScrollView setBouncesZoom:YES];
[[self view] addSubview:imageScrollView];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"WeCanDoIt.png"]];
[imageView setTag:ZOOM_VIEW_TAG];
[imageScrollView setContentSize:[imageView frame].size];
[imageScrollView addSubview:imageView];
CGSize imageSize = imageView.image.size;
[imageView release];
CGSize maxSize = imageScrollView.frame.size;
CGFloat widthRatio = maxSize.width / imageSize.width;
CGFloat heightRatio = maxSize.height / imageSize.height;
CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;
[imageScrollView setMinimumZoomScale:initialZoom];
[imageScrollView setZoomScale:1];
float topInset = (maxSize.height - imageSize.height) / 2.0;
float sideInset = (maxSize.width - imageSize.width) / 2.0;
if (topInset < 0.0) topInset = 0.0;
if (sideInset < 0.0) sideInset = 0.0;
[imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [imageScrollView viewWithTag:ZOOM_VIEW_TAG];
}
/************************************** NOTE **************************************/
/* The following delegate method works around a known bug in zoomToRect:animated: */
/* In the next release after 3.0 this workaround will no longer be necessary */
/**********************************************************************************/
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
[scrollView setZoomScale:scale+0.01 animated:NO];
[scrollView setZoomScale:scale animated:NO];
// END Bug workaround
CGSize maxSize = imageScrollView.frame.size;
CGSize viewSize = view.frame.size;
float topInset = (maxSize.height - viewSize.height) / 2.0;
float sideInset = (maxSize.width - viewSize.width) / 2.0;
if (topInset < 0.0) topInset = 0.0;
if (sideInset < 0.0) sideInset = 0.0;
[imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
}
Réponses:
J'ai une solution très simple! Tout ce dont vous avez besoin est de mettre à jour le centre de votre sous-vue (imageview) tout en zoomant dans ScrollViewDelegate. Si l'image agrandie est plus petite que scrollview, ajustez subview.center sinon le centre est (0,0).
la source
CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0);
CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentInset.left - scrollView.contentInset.right - scrollView.contentSize.width) * 0.5, 0.0); CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentInset.top - scrollView.contentInset.bottom - scrollView.contentSize.height) * 0.5, 0.0);
zoomToRect:
. L'utilisation de l'contentInset
approche fonctionne mieux si vous avez besoin de cette fonctionnalité. Voir petersteinberger.com/blog/2013/how-to-center-uiscrollview pour plus de détails.La réponse de @ EvelynCordner était celle qui fonctionnait le mieux dans mon application. Beaucoup moins de code que les autres options aussi.
Voici la version Swift si quelqu'un en a besoin:
la source
D'accord, je me suis battu contre ça ces deux derniers jours de temps en temps et étant finalement arrivé à une solution assez fiable (jusqu'à présent ...), j'ai pensé que je devrais la partager et éviter aux autres de souffrir. :) Si vous trouvez un problème avec cette solution, criez!
J'ai essentiellement parcouru ce que tout le monde a: en recherchant StackOverflow, les forums de développeurs Apple, j'ai regardé le code pour three20, ScrollingMadness, ScrollTestSuite, etc. du ViewController, etc. mais rien n'a fonctionné à merveille (comme tout le monde l'a découvert aussi).
Après avoir dormi dessus, j'ai essayé quelques angles alternatifs:
Avec cette méthode UIScrollView de sous-classification, je remplace le mutateur contentOffset afin qu'il ne définisse pas {0,0} lorsque l'image est redimensionnée plus petite que la fenêtre - au lieu de cela, il définit le décalage de sorte que l'image reste centrée dans la fenêtre. Jusqu'à présent, cela semble toujours fonctionner. Je l'ai vérifié avec des images larges, hautes, minuscules et grandes et je n'ai pas le problème "fonctionne mais le pincement au zoom minimum le casse".
J'ai téléchargé un exemple de projet sur github qui utilise cette solution, vous pouvez le trouver ici: http://github.com/nyoron/NYOBetterZoom
la source
anOffset.y = -(scrollViewSize.height - zoomViewSize.height) / 2.0
enanOffset.y = (-(scrollViewSize.height - zoomViewSize.height) / 2.0) + 10;
Ce code devrait fonctionner sur la plupart des versions d'iOS (et a été testé pour fonctionner à partir de la version 3.1).
Il est basé sur le code WWDC d'Apple pour le photoscoller.
Ajoutez ce qui suit à votre sous-classe de UIScrollView et remplacez tileContainerView par la vue contenant votre image ou vos mosaïques:
la source
UIScrollView
approche de sous - classe semble préférable: elle est invoquée lorsque la vue est affichée pour la première fois + en continu pendant que le zoom est en cours (alors qu'ellescrollViewDidZoom
n'est invoquée qu'une seule fois par scroll et après le fait)Pour une solution mieux adaptée aux vues de défilement qui utilisent la disposition automatique, utilisez des encarts de contenu de la vue de défilement plutôt que de mettre à jour les cadres des sous-vues de votre vue de défilement.
la source
UIView
qui se trouve à l'intérieur duUIScrollview
au même centre (view.center = scrollview.center;
), puis dans l'scrollViewDidZoom
ensemble leview.frame.origin
x
ety
à0
nouveau.dispatch_async
dans la file d'attente principale dansviewWillAppear
laquelle j'appellescrollViewDidZoom:
ma vue de défilement principale. Cela fait apparaître la vue avec des images centrées.viewDidLayoutSubviews
pour vous assurer qu'il est correctement configuré lorsque la vue s'affiche pour la première fois.Actuellement, je sous
UIScrollView
- classe et remplacesetContentOffset:
pour ajuster le décalage en fonction decontentSize
. Il fonctionne à la fois avec le zoom par pincement et programmatique.En plus d'être court et doux, ce code produit un zoom beaucoup plus fluide que la solution @Erdemus. Vous pouvez le voir en action dans la démo RMGallery .
la source
J'ai passé une journée à me battre avec ce problème et j'ai fini par implémenter le scrollViewDidEndZooming: withView: atScale: comme suit:
Cela garantit que lorsque l'image est plus petite que l'écran, il y a encore suffisamment d'espace autour d'elle pour que vous puissiez la positionner à l'endroit exact que vous voulez.
(en supposant que votre UIScrollView contient un UIImageView pour contenir l'image)
Essentiellement, cela vérifie si la largeur / hauteur de votre image est plus petite que la largeur / hauteur de l'écran, et si c'est le cas, créez un encart de la moitié de la largeur / hauteur de l'écran (vous pourriez probablement l'agrandir si vous voulez que l'image sortir des limites de l’écran).
Notez que puisqu'il s'agit d'une méthode UIScrollViewDelegate , n'oubliez pas de l'ajouter à la déclaration de votre contrôleur de vue, afin d'éviter d'avoir un problème de construction.
la source
Apple a publié les vidéos de la session 2010 de la WWDC à tous les membres du programme de développement iPhone. L'un des sujets abordés est la façon dont ils ont créé l'application photos !!! Ils créent une application très similaire étape par étape et ont rendu tout le code disponible gratuitement.
Il n'utilise pas non plus l'API privée. Je ne peux mettre aucun code ici en raison de l'accord de non-divulgation, mais voici un lien vers l'exemple de téléchargement de code. Vous devrez probablement vous connecter pour y accéder.
http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645
Et voici un lien vers la page iTunes WWDC:
http://insideapple.apple.com/redir/cbx-cgi.do?v=2&la=en&lc=&a=kGSol9sgPHP%2BtlWtLp%2BEP%2FnxnZarjWJglPBZRHd3oDbACudP51JNGS8KlsFgxZto9X%2BTsnqSbeUSWX0doe%2Fzv%2FN5XV55%2FomsyfRgFBysOnIVggO%2Fn2p%2BiweDK%2F%2FmsIXj
la source
Ok, cette solution fonctionne pour moi. J'ai une sous-classe de
UIScrollView
avec une référence à celleUIImageView
qu'il affiche. Chaque fois que lesUIScrollView
zooms, la propriété contentSize est ajustée. C'est dans le setter que je mets à l'échelle deUIImageView
manière appropriée et ajuste également sa position centrale.Evertime je place l'image sur le
UIScrollView
je la redimensionne. LeUIScrollView
dans la vue de défilement est également une classe personnalisée que j'ai créée.Avec ces deux méthodes, je peux avoir une vue qui se comporte comme l'application de photos.
la source
La façon dont j'ai fait cela est d'ajouter une vue supplémentaire dans la hiérarchie:
Donnez-vous
UIView
le même rapport hauteur / largeur que le vôtreUIScrollView
et centrez-leUIImageView
sur cela.la source
Je sais que certaines réponses ci-dessus sont exactes, mais je veux juste donner ma réponse avec quelques explications, les commentaires vous feront comprendre pourquoi nous aimons ça.
Lorsque je charge le scrollView pour la première fois, j'écris le code suivant pour le centrer, veuillez noter que nous définissons d'
contentOffset
abord, puiscontentInset
Ensuite, lorsque je pince vContent, j'écris le code suivant pour le centrer.
la source
S'il
contentInset
n'est pas nécessaire pour autre chose, il peut être utilisé pour centrer le contenu de scrollview.Avantage si cette approche est que vous pouvez toujours utiliser
contentLayoutGuide
pour placer du contenu dans scrollviewou faites simplement glisser et déposez le contenu dans l'interface Builder de Xcode.
la source
Vous pouvez observer la
contentSize
propriété de UIScrollView (à l'aide de l'observation de valeur-clé ou similaire) et ajuster automatiquementcontentInset
chaque fois que lescontentSize
modifications sont inférieures à la taille de la vue de défilement.la source
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
(décrit à developer.apple.com/iphone/library/documentation/UIKit/… ), mais je préférerais observercontentSize
parce que sinon vous finirez par abandonner la nouvelle échelle de zoom et la trouver de toute façon de la vue. (Sauf si vous pouvez réaliser des calculs géniaux basés sur la taille relative de vos vues.)Voici une manière élégante de centrer le contenu de
UISCrollView
.Ajoutez un observateur au contentSize de votre
UIScrollView
, donc cette méthode sera appelée à chaque fois que le contenu change ...Maintenant sur votre méthode d'observateur:
Vous devriez changer le
[pointer viewWithTag:100]
. Remplacez par votre vue de contenuUIView
.imageGallery
indiquant la taille de votre fenêtre.Cela corrigera le centre du contenu à chaque fois que sa taille changera.
REMARQUE: la seule façon dont ce contenu ne fonctionne pas très bien est avec la fonctionnalité de zoom standard du
UIScrollView
.la source
C'est ma solution à ce problème qui fonctionne assez bien pour tout type de vue à l'intérieur d'un scrollview.
la source
Il y a beaucoup de solutions ici, mais je risquerais de mettre ici les miennes. C'est bon pour deux raisons: cela ne gâche pas l'expérience de zoom, comme le ferait la mise à jour du cadre de vue d'image en cours, et il respecte également les encarts de vue de défilement d'origine (par exemple, définis dans xib ou storyboard pour une gestion gracieuse des barres d'outils semi-transparentes, etc.) .
Tout d'abord, définissez un petit assistant:
Pour conserver les encarts d'origine, champ défini:
Et quelque part dans viewDidLoad, remplissez-le:
Pour placer UIImageView dans UIScrollView (en supposant que UIImage lui-même est dans la variable sharedImage):
scrollViewDidZoom: à partir de UIScrollViewDelegate pour cette vue de défilement:
Un enfin, se centrant:
Je n'ai pas encore testé le changement d'orientation (c'est-à-dire la réaction appropriée pour redimensionner UIScrollView lui-même), mais le corriger devrait être relativement facile.
la source
Vous constaterez que la solution publiée par Erdemus fonctionne, mais… Il y a des cas où la méthode scrollViewDidZoom n'est pas invoquée et votre image est bloquée dans le coin supérieur gauche. Une solution simple consiste à invoquer explicitement la méthode lorsque vous affichez initialement une image, comme ceci:
Dans de nombreux cas, vous pouvez invoquer cette méthode deux fois, mais il s'agit d'une solution plus propre que certaines des autres réponses de cette rubrique.
la source
L'exemple de défilement photo d'Apple fait exactement ce que vous recherchez. Mettez ceci dans votre sous-classe UIScrollView et changez _zoomView en votre UIImageView.
Exemple de code de défilement photo d'Apple
la source
Pour que l'animation se déroule correctement, définissez
et utilisez cette fonction (trouver le centre en utilisant la méthode à cette réponse )
Cela crée un effet de rebond mais n'implique aucun mouvement brusque au préalable.
la source
Juste la réponse approuvée en rapide, mais sans sous-classement en utilisant le délégué
la source
Dans le cas où votre imageView interne a une largeur spécifique initiale (par exemple 300) et que vous souhaitez simplement centrer sa largeur uniquement sur un zoom plus petit que sa largeur initiale, cela peut également vous aider.
la source
Voici la façon dont je fais ce travail actuellement. C'est mieux mais toujours pas parfait. Essayez de régler:
pour résoudre le problème avec la vue ne se centrant pas à
minZoomScale
.De plus, je fais ce qui suit pour empêcher l'image de coller sur le côté après un zoom arrière.
la source
D'accord, je pense avoir trouvé une assez bonne solution à ce problème. L'astuce consiste à réajuster constamment le
imageView's
cadre. Je trouve que cela fonctionne beaucoup mieux que d'ajuster constamment lecontentInsets
oucontentOffSets
. J'ai dû ajouter un peu de code supplémentaire pour accueillir les images portrait et paysage.Voici le code:
la source
Désactivez simplement la pagination pour que cela fonctionne correctement:
la source
J'ai eu exactement le même problème. Voici comment j'ai résolu
Ce code devrait être appelé à la suite de
scrollView:DidScroll:
la source
Bien que la question soit un peu ancienne, le problème existe toujours. Je l'ai résolu dans Xcode 7 en faisant la contrainte d'espace vertical de l'élément le plus haut (dans ce cas le
topLabel
) aux superViews (lescrollView
) en hautIBOutlet
, puis en recalculant sa constante chaque fois que le contenu change en fonction de la hauteur des sous-vues de scrollView (topLabel
etbottomLabel
).la source