Hoe kan ik opnieuw in te stellen na een UIScrollView zoom?

stemmen
15

Ik heb een grafiek in een getrokken UIScrollView. Het is een groot UIViewgebruik van een aangepaste subklasse van CATiledLayerals zijn laag.

Toen ik in en uit het zoomen UIScrollView, wil ik de grafiek om het formaat dynamisch zoals het hoort als ik de grafiek van terug te keren viewForZoomingInScrollView. Echter, de grafiek tekent zich op het nieuwe zoomniveau, en ik wil het resetten van de te transformeren schaal 1x1, zodat de volgende keer dat de gebruiker inzoomt, het begint te transformeren van de huidige weergave. Als ik reset het transformeren naar identiteit in scrollViewDidEndZooming, het werkt in de simulator, maar genereert een EXC_BAD_ACCSESop het apparaat.

Dit heeft niet eens het probleem opgelost volledig op de simulator ook niet, want de volgende keer dat de gebruiker inzoomt, de transformatie reset zelf aan wat zoomniveau het was op, en dus het lijkt erop dat, als ik werd ingezoomd tot 2x, bijvoorbeeld, het is plotseling op 4x. Als ik klaar ben met de zoom, het eindigt op de juiste schaal, maar de feitelijke handeling van zoomen ziet er slecht uit.

Dus eerst: hoe sta ik de grafiek om zichzelf opnieuw te tekenen bij de standaard schaal van 1x1 na zoomen, en hoe kan ik een gladde zoom overal?

Edit: Nieuwe bevindingen De fout lijkt te zijn [CALayer retainCount]: message sent to deallocated instance

Ik ben nooit deallocating elke lagen mezelf. Voor, ik was niet eens met weglating van alle standpunten of wat dan ook. Deze fout werd gegooid op Zoom en ook op draaien. daarna als ik het object voor rotatie en verwijderen re-toe te voegen, is het niet de uitzondering gooien. Dit is geen optie voor zoomen.

De vraag is gesteld op 15/01/2009 om 21:16
bron van user
In andere talen...                            


7 antwoorden

stemmen
41

Ik kan u niet helpen met de crashen, anders dan u vertellen om te controleren en zorg ervoor dat u niet per ongeluk autoreleasing het oog of een laag ergens in uw code. Ik heb gezien dat de simulator omgaan met de timing van autoreleases anders dan op het toestel (meestal bij discussies betrokken zijn).

Het uitzicht scaling is een probleem met UIScrollViewdie ik heb tegenkomen, dat wel. Tijdens een pinch-zoomen event, UIScrollViewzal het uitzicht u in het nemen viewForZoomingInScrollView:delegeren methode en breng een transformeren naar het. Deze transformatie een glad schaling van het oog zonder het opnieuw te tekenen elk frame. Aan het einde van de zoom operatie, uw afgevaardigde methode scrollViewDidEndZooming:withView:atScale:zal worden genoemd en geven u een kans om een meer hoogwaardige weergave van uw weergave te doen op de nieuwe schaal factor. In het algemeen, het is gesuggereerd dat je reset de transformatie van uw oog te zijn CGAffineTransformIdentityen dan heb je uitzicht zelf handmatig opnieuw te tekenen op het nieuwe formaat schaal.

Dit veroorzaakt echter een probleem omdat UIScrollViewniet lijkt te zien op de inhoud uitzicht te transformeren, zodat op de volgende zoomwerking het zet de transformatie van de inhoud om, ongeacht de totale omvang factor is. Aangezien u handmatig uw zicht hebt getekend op het laatste schaal factor, dat verbindingen de schaal, dat is wat je ziet.

Als tijdelijke oplossing, gebruik ik een UIView subklasse voor mijn inhoud bekijken met de volgende methoden bepaald:

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

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

waarbij previousScale een float instantievariabele van de weergave. Vervolgens voeren de I inzoomen gemachtigde werkwijze als volgt:

- (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;
}

Hierdoor worden de transformaties naar de inhoud weergave aangepast op basis van de schaal waarop de weergave het laatst hertekend. Wanneer de pinch-zoomen gebeurt, de transformatie weer op een schaal van 1,0 met omzeiling van de aanpassing in de normale setTransform:werkwijze. Dit lijkt de juiste schaling gedrag te bieden, terwijl u te laten een scherpe weergave te tekenen bij de voltooiing van een zoom.

UPDATE (7/23/2010): iPhone OS 3.2 en hoger hebben het gedrag van standpunten scroll veranderd met betrekking tot zoomen. Nu, UIScrollViewzal de identiteit respecteren transformatie u zich wenden tot een content bekijken en alleen de relatieve schaal factor in -scrollViewDidEndZooming:withView:atScale:. Daarom is de bovenstaande code voor een UIViewsubklasse is alleen nodig voor apparaten die draaien op iPhone OS-versies ouder dan 3.2.

antwoordde op 16/01/2009 om 20:29
bron van user

stemmen
12

Dank aan alle eerdere antwoorden, en hier is mijn oplossing.
Implementeren 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 is mijn subklasse van UIView
  • tmvScrollView - uitlaat UIScrollView
  • set maximumZoomScale en minimumZoomScale alvorens
  • maak previousScale instantievariabele en zet de waarde op 1.0F

Werkt voor mij perfect.

BR, Eugene.

antwoordde op 02/08/2011 om 17:33
bron van user

stemmen
5

Ik heb een gedetailleerde bespreking van hoe (en waarom) UIScrollView zoomen werkt bij github.com/andreyvit/ScrollingMadness/ .

(De link bevat ook een beschrijving van het programmatisch zoomen UIScrollView, hoe te emuleren fotobibliotheek-stijl paging + zoomen + scrollen, een voorbeeld project en ZoomScrollView klasse die een aantal van de zoomen magie inkapselt.)

Citaat:

UIScrollView heeft geen notie van een “huidige zoomniveau”, omdat elke subweergave het bevat kan zijn eigen huidige zoomniveau te hebben. Merk op dat er geen veld in UIScrollView om het huidige zoomniveau te houden. Maar we weten dat iemand slaat dat zoomniveau, want als je pinch-zoom een ​​subweergave, stel dan haar te transformeren naar CGAffineTransformIdentity, en dan knijpen weer, zult u merken dat de vorige zoomniveau van de subview is hersteld.

Sterker nog, als je kijkt naar de demontage, het is UIView dat haar eigen zoomniveau slaat (binnen UIGestureInfo object waarnaar wordt verwezen door het veld _gestureInfo). Het heeft ook een aantal leuke ongedocumenteerde methoden zoals zoomScaleen setZoomScale:animated:. (Let wel, het heeft ook een heleboel-rotatie-gerelateerde methoden, misschien krijgen we rotatie gebaar ondersteuning voor bepaalde dag snel.)

Echter, als we een nieuwe UIView enkel voor zoomen en voeg onze echte zoomable uitzicht als zijn kind, zullen we beginnen altijd met zoomniveau 1,0. Mijn implementatie van programmatische zoomen is gebaseerd op deze truc.

antwoordde op 08/05/2009 om 00:04
bron van user

stemmen
4

Ik was gewoon op zoek om opnieuw in te stellen van de belasting op standaard zoom schaal, want als ik inzoomen het, ScrollView is het hebben van dezelfde zoomschaal voor de volgende keer, totdat het wordt deallocated.

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

Veranderde het spel.

antwoordde op 03/06/2015 om 06:53
bron van user

stemmen
3

Een redelijk betrouwbare aanpak, die geschikt naar iOS 3.2 en 4.0 en hoger, is als volgt. Je moet bereid schaalbare weergave (de chief subweergave van de scroll view) leveren in iedere gewenste schaal. Toen in scrollViewDidEndZooming:zul je de vage schaal getransformeerd versie van deze visie te verwijderen en te vervangen door een nieuwe blik gevestigd op de nieuwe schaal.

Je zal nodig hebben:

  • Een ivar voor het handhaven van de vorige schaal; laten we noemen het oldScale

  • Een manier voor het identificeren van de schaalbare weergave, zowel viewForZoomingInScrollView:als voor scrollViewDidEndZooming:; hier, ik ga om een tag toe te passen (999)

  • Een methode die de schaalbare uitzicht creëert, labels, en voegt het in de scroll weergave (hier is zal ik het noemen addNewScalableViewAtScale:). Vergeet niet, het moet er alles aan doen op schaal - het maten van het uitzicht en de subviews of tekening, en maten contentSize de scroll het standpunt van het aan te passen.

  • Constanten voor de minimumZoomScale en maximumZoomScale. Deze zijn nodig, want als we de geschaalde weergave te vervangen door de gedetailleerde grotere versie, het systeem gaat om te denken dat de huidige schaal is 1, dus we moeten de gek te houden zodat de gebruiker van het uitzicht terug naar beneden te schalen.

Heel goed dan. Wanneer u de scroll weergave wilt maken, dan plaatst u de schaalbare uitzicht op schaal 1.0. Dit kan in je viewDidLoad, bijvoorbeeld ( svhet scroll view):

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

Vervolgens in uw scrollViewDidEndZooming:doe je hetzelfde, maar compenseren voor de verandering in de schaal:

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;
antwoordde op 12/11/2010 om 06:33
bron van user

stemmen
2

Merk op dat de door Brad oplossing heeft één probleem echter: als je blijft programmatisch inzoomen (laten we zeggen op dubbele tik event) en laat gebruiker handmatig (pinch-out) uitzoomt, na verloop van tijd het verschil tussen de werkelijke omvang en de schaal UIScrollView is het bijhouden zal te groot groeien, dus het previousScalezal op een bepaald punt val van precisie float's die uiteindelijk zal resulteren in een onvoorspelbaar gedrag

antwoordde op 28/07/2009 om 04:43
bron van user

stemmen
0

* 4. snelle en Xcode 9.3

Instellen ScrollView zoomschaal op 0 zal uw ScrollView teruggezet naar het oorspronkelijke staat.

self.scrollView.setZoomScale(0.0, animated: true)
antwoordde op 29/06/2018 om 05:21
bron van user

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more