Ich habe eine UIImageView
Innenseite, UIScrollView
die ich zum Zoomen und Scrollen verwende. Wenn das Bild / der Inhalt der Bildlaufansicht größer als die Bildlaufansicht ist, funktioniert alles einwandfrei. Wenn das Bild jedoch kleiner als die Bildlaufansicht wird, bleibt es in der oberen linken Ecke der Bildlaufansicht. Ich möchte es zentriert halten, wie die Fotos-App.
Irgendwelche Ideen oder Beispiele, wie man den Inhalt des UIScrollView
Zentrums beibehalten kann, wenn er kleiner ist?
Ich arbeite mit iPhone 3.0.
Der folgende Code funktioniert fast. Das Bild kehrt in die obere linke Ecke zurück, wenn ich es nach Erreichen der minimalen Zoomstufe kneife.
- (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)];
}
Antworten:
Ich habe eine sehr einfache Lösung! Sie müssen lediglich die Mitte Ihrer Unteransicht (Bildansicht) aktualisieren, während Sie das ScrollViewDelegate vergrößern. Wenn das gezoomte Bild kleiner als die Bildlaufansicht ist, passen Sie die Unteransicht an. Das Zentrum ist sonst (0,0).
quelle
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:
. Die Verwendung descontentInset
Ansatzes funktioniert besser, wenn Sie diese Funktionalität benötigen. Weitere Informationen finden Sie unter petersteinberger.com/blog/2013/how-to-center-uiscrollview .@ EvelynCordners Antwort war die, die in meiner App am besten funktioniert hat. Viel weniger Code als die anderen Optionen.
Hier ist die Swift-Version, falls jemand sie benötigt:
quelle
Okay, ich habe in den letzten zwei Tagen immer wieder dagegen gekämpft und war endlich zu einer ziemlich zuverlässigen (bisher ...) Lösung gekommen. Ich dachte, ich sollte sie teilen und anderen etwas Schmerz ersparen. :) Wenn Sie ein Problem mit dieser Lösung finden, rufen Sie bitte!
Ich habe im Grunde genommen alles durchgesehen, was alle anderen haben: StackOverflow durchsuchen, die Apple Developer Forums durchsuchen, den Code nach three20, ScrollingMadness, ScrollTestSuite usw. durchsuchen. Ich habe versucht, den UIImageView-Frame zu vergrößern und mit dem Offset und / oder den Insets von UIScrollView zu spielen vom ViewController usw., aber nichts hat großartig funktioniert (wie alle anderen auch herausgefunden haben).
Nachdem ich darauf geschlafen hatte, versuchte ich ein paar alternative Blickwinkel:
Mit dieser UIScrollView-Methode der Unterklasse überschreibe ich den Mutator contentOffset, damit nicht {0,0} festgelegt wird, wenn das Bild kleiner als das Ansichtsfenster skaliert wird. Stattdessen wird der Versatz so festgelegt, dass das Bild im Ansichtsfenster zentriert bleibt. Bisher scheint es immer zu funktionieren. Ich habe es mit breiten, großen, winzigen und großen Bildern überprüft und habe nicht das Problem "funktioniert, aber bei minimalem Zoom zu kneifen bricht es".
Ich habe ein Beispielprojekt auf github hochgeladen, das diese Lösung verwendet. Sie finden es hier: http://github.com/nyoron/NYOBetterZoom
quelle
anOffset.y = -(scrollViewSize.height - zoomViewSize.height) / 2.0
inanOffset.y = (-(scrollViewSize.height - zoomViewSize.height) / 2.0) + 10;
Dieser Code sollte auf den meisten Versionen von iOS funktionieren (und wurde getestet, um auf 3.1 oder höher zu funktionieren).
Es basiert auf dem Apple WWDC-Code für den Photoscoller.
Fügen Sie Ihrer Unterklasse von UIScrollView Folgendes hinzu und ersetzen Sie tileContainerView durch die Ansicht, die Ihr Bild oder Ihre Kacheln enthält:
quelle
UIScrollView
Unterklassenansatz scheint vorzuziehen: Er wird aufgerufen, wenn die Ansicht zum ersten Mal + kontinuierlich angezeigt wird, während das Zoomen ausgeführt wird (während siescrollViewDidZoom
nur einmal pro Bildlauf und nachträglich aufgerufen wird)Verwenden Sie für eine Lösung, die besser für Bildlaufansichten mit automatischem Layout geeignet ist, Inhaltseinfügungen der Bildlaufansicht, anstatt die Frames der Unteransichten Ihrer Bildlaufansicht zu aktualisieren.
quelle
UIView
dass die ist innenUIScrollview
mit dem gleichen Mittelpunkt (view.center = scrollview.center;
) und dann in derscrollViewDidZoom
die Mengeview.frame.origin
x
undy
zu0
wieder.dispatch_async
an die Hauptwarteschlange gesendet, in derviewWillAppear
ichscrollViewDidZoom:
meine Hauptscrollansicht aufrufe. Dadurch wird die Ansicht mit zentrierten Bildern angezeigt.viewDidLayoutSubviews
, um sicherzustellen, dass er ordnungsgemäß eingerichtet ist, wenn die Ansicht zum ersten Mal angezeigt wird.Derzeit bin ich Unterklasse
UIScrollView
und überschreibesetContentOffset:
, um den Versatz basierend auf anzupassencontentSize
. Es funktioniert sowohl mit Prise als auch mit programmgesteuertem Zoomen.Dieser Code ist nicht nur kurz und bündig, sondern erzeugt auch einen viel weicheren Zoom als die @ Erdemus-Lösung. Sie können es in der RMGallery- Demo in Aktion sehen .
quelle
Ich habe einen Tag lang mit diesem Problem gekämpft und am Ende das scrollViewDidEndZooming: withView: atScale: wie folgt implementiert :
Dies stellt sicher, dass, wenn das Bild kleiner als der Bildschirm ist, immer noch genügend Platz um das Bild herum vorhanden ist, damit Sie es genau an der gewünschten Stelle positionieren können.
(vorausgesetzt, Ihre UIScrollView enthält eine UIImageView, um das Bild aufzunehmen)
Im Wesentlichen wird dabei überprüft, ob die Breite / Höhe Ihrer Bildansicht kleiner als die Breite / Höhe des Bildschirms ist, und in diesem Fall ein Einschub mit der Hälfte der Breite / Höhe des Bildschirms erstellt (Sie können diesen wahrscheinlich vergrößern, wenn Sie das Bild möchten die Bildschirmgrenzen verlassen).
Da es sich um eine UIScrollViewDelegate- Methode handelt, vergessen Sie nicht, sie der Deklaration Ihres View Controllers hinzuzufügen, um ein Build-Problem zu vermeiden.
quelle
Apple hat die WWDC-Sitzungsvideos 2010 für alle Mitglieder des iPhone-Entwicklerprogramms veröffentlicht. Eines der besprochenen Themen ist, wie sie die Foto-App erstellt haben !!! Sie erstellen Schritt für Schritt eine sehr ähnliche App und haben den gesamten Code kostenlos zur Verfügung gestellt.
Es wird auch keine private API verwendet. Ich kann wegen der Geheimhaltungsvereinbarung keinen Code hier einfügen, aber hier ist ein Link zum Beispielcode-Download. Sie müssen sich wahrscheinlich anmelden, um Zugriff zu erhalten.
http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645
Und hier ist ein Link zur iTunes WWDC-Seite:
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
quelle
Ok, diese Lösung funktioniert bei mir. Ich habe eine Unterklasse
UIScrollView
mit einem Verweis auf dieUIImageView
angezeigte. BeiUIScrollView
jedem Zoomen wird die contentSize-Eigenschaft angepasst. Im Setter skaliere ich dasUIImageView
entsprechend und stelle auch seine Mittelstellung ein.Über die Zeit habe ich das Bild so eingestellt, dass
UIScrollView
ich die Größe ändere . DieUIScrollView
in der Bildlaufansicht ist auch eine benutzerdefinierte Klasse, die ich erstellt habe.Mit diesen beiden Methoden kann ich eine Ansicht erstellen, die sich genau wie die Foto-App verhält.
quelle
Ich habe dies getan, um der Hierarchie eine zusätzliche Ansicht hinzuzufügen:
Geben Sie Ihr
UIView
Seitenverhältnis anUIScrollView
und zentrieren SieUIImageView
es.quelle
Ich weiß, dass einige der obigen Antworten richtig sind, aber ich möchte meine Antwort nur mit einer Erklärung geben. Die Kommentare werden Ihnen verständlich machen, warum uns das gefällt.
Wenn ich die scrollView zum ersten Mal lade, schreibe ich den folgenden Code, um sie zu zentrieren. Bitte beachten Sie, dass wir dann
contentOffset
zuerst festlegencontentInset
Wenn ich dann vContent kneife, schreibe ich den folgenden Code, um ihn zu zentrieren.
quelle
Wenn
contentInset
es für nichts anderes benötigt wird, kann es verwendet werden, um den Inhalt der Bildlaufansicht zu zentrieren.Vorteil dieses Ansatzes ist, dass Sie weiterhin
contentLayoutGuide
Inhalte in der Bildlaufansicht platzieren könnenoder ziehen Sie den Inhalt einfach per Drag & Drop in den Interface Builder von Xcode.
quelle
Sie können die
contentSize
Eigenschaft von UIScrollView (mithilfe von Schlüsselwertbeobachtung oder ähnlichem) beobachten und automatisch anpassen,contentInset
wenn diecontentSize
Änderungen kleiner als die Größe der Bildlaufansicht sind.quelle
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
(beschrieben unter developer.apple.com/iphone/library/documentation/UIKit/… ), aber ich würde es vorziehen, dies zu beobachten,contentSize
da Sie sonst die neue Zoomskala verwerfen und sie trotzdem aus der Ansicht finden. (Es sei denn, Sie können einige großartige Berechnungen basierend auf den relativen Größen Ihrer Ansichten durchführen.)Eine elegante Möglichkeit, den Inhalt von zu zentrieren,
UISCrollView
ist diese.Fügen Sie einen Beobachter zur Inhaltsgröße von hinzu
UIScrollView
, sodass diese Methode jedes Mal aufgerufen wird, wenn sich der Inhalt ändert ...Nun zu Ihrer Beobachtermethode:
Sie sollten das ändern
[pointer viewWithTag:100]
. Durch Ihre Inhaltsansicht ersetzenUIView
.imageGallery
Zeigen auf Ihre Fenstergröße.Dadurch wird die Mitte des Inhalts jedes Mal korrigiert, wenn sich seine Größe ändert.
HINWEIS: Der einzige Weg, wie dieser Inhalt nicht sehr gut funktioniert, ist die Standard-Zoomfunktion des
UIScrollView
.quelle
Dies ist meine Lösung für dieses Problem, das für jede Art von Ansicht in einer Bildlaufansicht ziemlich gut funktioniert.
quelle
Hier gibt es viele Lösungen, aber ich würde riskieren, meine eigenen hier zu platzieren. Es ist aus zwei Gründen gut: Es beeinträchtigt nicht das Zoomen, ebenso wie das Aktualisieren des laufenden Bildansichtsrahmens, und es berücksichtigt auch die ursprünglichen Bildlaufansichten (z. B. in xib oder Storyboard definiert, um eine halbtransparente Symbolleiste usw. ordnungsgemäß zu handhaben). .
Definieren Sie zunächst einen kleinen Helfer:
Um die ursprünglichen Einfügungen beizubehalten, definiertes Feld:
Und irgendwo in viewDidLoad füllen Sie es:
So platzieren Sie UIImageView in UIScrollView (vorausgesetzt, UIImage selbst befindet sich in loadImage var):
scrollViewDidZoom: aus UIScrollViewDelegate für diese Bildlaufansicht:
Und schließlich zentriert sich:
Ich habe die Orientierungsänderung noch nicht getestet (dh die richtige Reaktion zum Ändern der Größe von UIScrollView selbst), aber die Lösung sollte relativ einfach sein.
quelle
Sie werden feststellen, dass die von Erdemus veröffentlichte Lösung funktioniert, aber… In einigen Fällen wird die scrollViewDidZoom-Methode nicht aufgerufen und Ihr Bild bleibt in der oberen linken Ecke hängen. Eine einfache Lösung besteht darin, die Methode explizit aufzurufen, wenn Sie ein Bild zum ersten Mal anzeigen, wie folgt:
In vielen Fällen rufen Sie diese Methode möglicherweise zweimal auf, dies ist jedoch eine sauberere Lösung als einige der anderen Antworten in diesem Thema.
quelle
Apples Photo Scroller-Beispiel macht genau das, wonach Sie suchen. Fügen Sie dies in Ihre UIScrollView-Unterklasse ein und ändern Sie _zoomView in Ihre UIImageView.
Beispielcode für den Apple Photo Scroller
quelle
Stellen Sie ein, damit die Animation gut fließt
und verwenden Sie diese Funktion (Finden des Zentrums mithilfe der Methode in dieser Antwort )
Dies erzeugt den Bouncing-Effekt, beinhaltet jedoch keine plötzlichen Bewegungen im Voraus.
quelle
Nur die genehmigte Antwort in Kürze, aber ohne Unterklasse mit dem Delegaten
quelle
Wenn Ihre innere imageView eine anfängliche spezifische Breite hat (z. B. 300) und Sie ihre Breite nur auf einen Zoom zentrieren möchten, der kleiner als seine anfängliche Breite ist, kann dies ebenfalls hilfreich sein.
quelle
Hier ist die aktuelle Art und Weise, wie ich diese Arbeit mache. Es ist besser, aber immer noch nicht perfekt. Versuchen Sie die Einstellung:
um das Problem zu beheben, dass die Ansicht nicht zentriert ist, wenn um
minZoomScale
.Außerdem gehe ich wie folgt vor, um zu verhindern, dass das Bild nach dem Herauszoomen an der Seite klebt.
quelle
Okay, ich denke, ich habe eine ziemlich gute Lösung für dieses Problem gefunden. Der Trick besteht darin, den
imageView's
Rahmen ständig neu einzustellen . Ich finde, das funktioniert viel besser, als dascontentInsets
oder ständig anzupassencontentOffSets
. Ich musste ein bisschen zusätzlichen Code hinzufügen, um sowohl Hoch- als auch Querformatbilder aufzunehmen.Hier ist der Code:
quelle
Deaktivieren Sie einfach die Paginierung, damit es gut funktioniert:
quelle
Ich hatte genau das gleiche Problem. Hier ist, wie ich gelöst habe
Dieser Code sollte als Ergebnis von aufgerufen werden
scrollView:DidScroll:
quelle
Obwohl die Frage etwas alt ist, besteht das Problem immer noch. Ich habe es in Xcode 7 gelöst, indem ich die vertikale Platzbeschränkung des obersten Elements (in diesem Fall des
topLabel
) auf die SuperViews (dasscrollView
) obenIBOutlet
und dann neu festgelegt habe und ihre Konstante jedes Mal neu berechnet habe, wenn sich der Inhalt abhängig von der Höhe der Unteransichten der scrollView (topLabel
und) ändertbottomLabel
).quelle