Frage

Ich habe ein Graph in einem UIScrollView gezogen werden. Es ist eine große UIView eine benutzerdefinierte Unterklasse von CATiledLayer als Schicht verwendet wird.

Wenn ich die Ansicht vergrößern und aus dem UIScrollView, möchte ich die Grafik dynamisch, um die Größe, wie es funktioniert, wenn ich die Grafik von viewForZoomingInScrollView zurückzukehren. Allerdings zeichnet die Grafik selbst an der neuen Zoomstufe, und ich möchte zurücksetzen die Waage 1x1 transformieren, so dass der nächste Mal, wenn der Benutzer zoomt, die beginnt, sich von der aktuellen Ansicht verwandeln. Wenn ich die in scrollViewDidEndZooming auf Identity-Transformation zurückgesetzt, es funktioniert im Simulator, sondern eine EXC_BAD_ACCSES auf dem Gerät führt.

Dies löst nicht einmal das Problem vollständig auf dem Simulator entweder, weil das nächste Mal, wenn der Benutzer zoomt, Ebene die Transformation setzt sich auf alles, was Zoom es war, und so sieht es aus wie, wenn ich 2x wurde gezoomt, zum Beispiel, dann ist es plötzlich mit 4x. Als ich den Zoom zu beenden, endet es in dem richtigen Maßstab, aber der eigentliche Akt des Zoomens sieht schlecht aus.

Also zuerst: Wie ermögliche ich der Grafik selbst bei der Standard-Skala von 1x1 neu zu zeichnen, nach dem Zoomen und wie habe ich einen glatten Zoom im gesamten

?

Bearbeiten: Neue Erkenntnisse Der Fehler scheint „[CALayer retainCount]: message sent to deallocated instance

zu sein

Ich bin ausplanen nie irgendwelche Schichten selbst. Vorher war ich nicht einmal alle Bemerkungen oder etwas zu löschen. Dieser Fehler wurde auf Zoom geworfen und auch auf drehen. Wenn ich das Objekt vor der Drehung und löschen erneut hinzufügen es später, es ist nicht die Ausnahme, nicht werfen. Dies ist keine Option zum Zoomen.

War es hilfreich?

Lösung

Ich kann Ihnen nicht mit dem Krachen helfen, andere, als Sie sagen, um zu überprüfen und sicherzustellen, dass Sie nicht ungewollt eine Ansicht autoreleasing oder irgendwo im Code Schicht. Ich habe der Simulator behandelt das Timing von autoreleases anders gesehen, als auf dem Gerät (meistens, wenn Threads beteiligt ist).

Die Ansicht Skalierung ist ein Thema, mit UIScrollView ich in laufen habe, though. Während einer Pinch-Zoom-Ereignis, nehmen UIScrollView die Ansicht, die Sie in der viewForZoomingInScrollView: Delegatmethode angegeben und gelten ein, um es zu transformieren. Diese Transformation liefert eine glatte Skalierung der Anzeige, ohne sie jedes Rahmens neu zu zeichnen ist. Am Ende der Zoom-Operation, wird Ihr Delegatmethode scrollViewDidEndZooming:withView:atScale: aufgerufen und gibt Ihnen eine Chance eine qualitativ hochwertige Wiedergabe Ihres Blick auf den neuen Skalierungsfaktor zu tun. Im Allgemeinen ist es empfohlen, dass Sie nach Ihrer Ansicht der Transformation zurückgesetzt werden CGAffineTransformIdentity und dann haben Ihre Ansicht selbst manuell im Maßstab neuen Größe neu gezeichnet werden.

Dies verursacht jedoch ein Problem, weil UIScrollView scheint nicht der Inhalt Ansicht verwandeln, so auf dem nächsten Zoomvorgang zu überwachen sie die Transformation der Inhaltsansicht setzt auf dem, was der Gesamtskalierungsfaktor ist. Da Sie manuell Ihre Ansicht im letzten Skalierungsfaktor neu gezeichnet haben, Verbindungen es die Skalierung, das ist, was Sie sehen.

Als Abhilfe kann, verwende ich eine UIView-Unterklasse für meine Inhalte Ansicht mit den folgenden Methoden definiert:

- (void)setTransformWithoutScaling:(CGAffineTransform)newTransform;
{
    [super setTransform:newTransform];
}

- (void)setTransform:(CGAffineTransform)newValue;
{
    [super setTransform:CGAffineTransformScale(newValue, 1.0f / previousScale, 1.0f / previousScale)];
}

wo previousScale ist ein Schwimmer Instanzvariable der Ansicht. Ich habe dann implementieren, um die Zoom Delegatmethode wie folgt:

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale;
{
    [contentView setTransformWithoutScaling:CGAffineTransformIdentity];
// Code to manually redraw view at new scale here
    contentView.previousScale = scale;
    scrollView.contentSize = contentView.frame.size;
}

Auf diese Weise wird die Transformationen auf den Inhalt Ansicht gesendet werden, basierend auf der Skala eingestellt, bei dem die Ansicht zuletzt neu gezeichnet war. Wenn die Pinch-Zoomen durchgeführt wird, die Transformation zu einer Skala von 1,0 zurückgestellt wird, indem die Verstellung in den Normal setTransform: Verfahren umgangen wird. Dies scheint die richtige Skalierungsverhalten zu liefern, während Sie einen knackigen Blick auf den Abschluss eines Zoom ziehen lassen.

UPDATE (7/23/2010): iPhone OS 3.2 und höher haben das Verhalten von Scroll-Ansichten in Bezug auf das Zoomen verändert. Nun wird respektiert ein UIScrollView die Identität verwandeln Sie einen Inhalt Ansicht anwenden und nur den relativen Skalierungsfaktor in -scrollViewDidEndZooming:withView:atScale: liefern. Deshalb ist der obige Code für eine UIView Unterklasse nur notwendig für Geräte mit iPhone OS-Versionen älter als 3.2.

Andere Tipps

Danke an alle bisherigen Antworten, und hier ist meine Lösung.
Implementieren Sie UIScrollViewDelegate Methoden:

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return tmv;
}

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
    CGPoint contentOffset = [tmvScrollView contentOffset];   
    CGSize  contentSize   = [tmvScrollView contentSize];
     CGSize  containerSize = [tmv frame].size;

    tmvScrollView.maximumZoomScale = tmvScrollView.maximumZoomScale / scale;
    tmvScrollView.minimumZoomScale = tmvScrollView.minimumZoomScale / scale;

    previousScale *= scale;

    [tmvScrollView setZoomScale:1.0f];

    [tmvScrollView setContentOffset:contentOffset];
    [tmvScrollView setContentSize:contentSize];
    [tmv setFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];  

    [tmv reloadData];
}
  • tmv ist meine Unterklasse von UIView
  • tmvScrollView - Ausgang zu UIScrollView
  • set maximumZoomScale und minimumZoomScale vor
  • Erstellen previousScale Instanzvariable und seinen Wert auf 1.0f

Funktioniert perfekt für mich.

BR, Eugene.

Ich war gerade auf der Suche nach Last zurücksetzen Zoomfaktor auf dem Standard, denn wenn ich es vergrößern, wird Scroll gleichen Zoomfaktor für die nächste Zeit mit, bis er freigegeben wird.

-(void) viewWillAppear:(BOOL)animated {
      [self.scrollView setZoomScale:1.0f];
}

Changed das Spiel.

Ich habe eine ausführliche Diskussion darüber, wie (und warum) UIScrollView Zoomen Arbeiten unter github.com/andreyvit/ScrollingMadness/ .

(Der Link enthält auch eine Beschreibung, wie UIScrollView programmatisch zoomen, wie Photo Library-Stil Paging + Zoom + Scrollen, ein Beispielprojekt und ZoomScrollView Klasse zu emulieren, die einen Teil der Zoom Magie kapselt.)

Zitat:

UIScrollView keinen Begriff einer „aktuellen Zoomstufe“, weil jeder es Subview enthält, kann seine eigene aktuelle Zoomstufe hat. Beachten Sie, dass in UIScrollView kein Feld die aktuelle Zoomstufe zu halten ist. Allerdings wissen wir, dass jemand, dass die Zoomstufe speichert, denn wenn man eine Subview Pinch-Zoom, dann setzen Sie seine zu CGAffineTransformIdentity verwandeln, und dann wieder kneifen, werden Sie feststellen, dass die vorherige Zoomstufe der subview restauriert wurde.

Ja, wenn man sich die Demontage betrachten, ist es UIView, die ihre eigene Zoomstufe speichert (innen UIGestureInfo Objekt durch das _gestureInfo Feld hingewiesen). Es hat auch eine Reihe von schönen undokumentierten Methoden wie zoomScale und setZoomScale:animated:. (Wohlgemerkt, es hat auch eine Reihe von Drehbezogenen Methoden, vielleicht bekommen wir Rotation Geste bald einen Tag unterstützen.)

Wenn wir jedoch eine neue UIView nur zum Zoomen und fügen Sie unsere reale zoombare Ansicht als sein Kind schaffen, werden wir immer mit Zoomstufe 1.0 starten. Meine Implementierung von programmatischen Zoomen basiert auf diesem Trick.

Ein ziemlich zuverlässiger Ansatz, angemessen auf iOS 3.2 und 4.0 und höher, ist wie folgt. Sie müssen bereit sein, Ihre skalierbare Ansicht (der Chef subview der Scroll-Ansicht) in jedem gewünschten Maßstab zu liefern. Dann in scrollViewDidEndZooming: finden Sie die unscharfe Scale-transformierte Version dieser Ansicht entfernen und durch eine neue Sicht auf die neue Skala gezogen ersetzen.

Sie benötigen:

  • Ein Ivar für den vorherigen Maßstab beibehalten wird; nennen wir es oldScale

  • Ein Weg, um die skalierbare Ansicht zu identifizieren, sowohl für viewForZoomingInScrollView: und scrollViewDidEndZooming:; hier, ich werde einen Tag (999)

  • anzuwenden
  • Eine Methode, die die skalierbare Ansicht, umbauten es schafft, und fügt es in der Scroll-Ansicht (hier nenne ich werde es addNewScalableViewAtScale:). Denken Sie daran, es muss alles tun, nach Maßstab -. Es Größen die Ansicht und seine Subviews oder Zeichnung und Größen der Content der Scroll-Ansicht übereinstimmen

  • Konstanten für die minimumZoomScale und maximumZoomScale. Diese werden benötigt, denn wenn wir die skalierte Ansicht durch die detaillierte größere Version ersetzen, das System denken wird, dass die aktuelle Skala 1 ist, so müssen wir es vorzutäuschen, die es dem Benutzer ermöglicht den Blick wieder nach unten zu skalieren.

Nun gut. Wenn Sie auf die Bildlaufansicht zu erstellen, legen Sie die skalierbare Ansicht im Maßstab 1,0. Dies könnte in Ihrem viewDidLoad sein, zum Beispiel (sv ist die Scroll-Ansicht):

[self addNewScalableViewAtScale: 1.0];
sv.minimumZoomScale = MIN;
sv.maximumZoomScale = MAX;
self->oldScale = 1.0;
sv.delegate = self;

Dann in Ihrem scrollViewDidEndZooming: Sie tun, um die gleiche Sache, aber für die Änderung der Skala Kompensation:

UIView* v = [sv viewWithTag:999];
[v removeFromSuperview];
CGFloat newscale = scale * self->oldScale;
self->oldScale = newscale;
[self addNewScalableViewAtScale:newscale];
sv.minimumZoomScale = MIN / newscale;
sv.maximumZoomScale = MAX / newscale;

Beachten Sie, dass die Lösung von Brad hat ein Problem zwar vorgesehen: wenn Sie programmatisch ein- halten (lassen Sie sich auf Doppel Antippereignis sagen) und lassen Sie Benutzer manuell (Auszwicken) verkleinern, nach einiger Zeit die Differenz zwischen dem wahren Maßstab und die Skala UIScrollView ist Tracking wachsen zu groß, so dass die previousScale wird irgendwann fällt aus float der Präzision, die schließlich in einem unvorhersehbaren Verhalten führt

Swift 4. * und Xcode 9.3

Einstellung Scrollzoomskala auf 0 zurückgesetzt Ihre Scroll es Anfangszustand ist.

self.scrollView.setZoomScale(0.0, animated: true)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top