Hvordan tilbakestiller jeg etter en UIScrollView zoom?

stemmer
15

Jeg har en graf som blir trukket i en UIScrollView. Det er en stor UIViewbruker et egendefinert underklasse av CATiledLayersom sitt lag.

Når jeg zoomer inn og ut av UIScrollView, jeg vil grafen for å endre størrelsen dynamisk som den gjør når jeg kommer tilbake grafen fra viewForZoomingInScrollView. Men tegner selve grafen på den nye zoom-nivå, og jeg ønsker å tilbakestille forvandle skala til 1x1, slik at neste gang brukeren zoomer, den trans starter fra gjeldende visning. Hvis jeg nullstille transformere til identitet i scrollViewDidEndZooming, det fungerer i simulatoren, men kaster en EXC_BAD_ACCSESpå enheten.

Dette betyr ikke selv løse problemet helt på simulatoren heller, fordi neste gang brukeren zoomer, den transtilbakestilles til hva zoom nivået den var på, og slik at det ser ut som om jeg var zoomet til 2x, for eksempel, det er plutselig på 4x. Når jeg er ferdig med zoom, ender det opp i riktig skala, men selve handlingen av zooming ser dårlig.

Så først: hvordan kan jeg tillate grafen for å tegne seg på standard skala fra 1x1 etter zooming, og hvordan kan jeg ha en jevn zoom hele?

Edit: Nye funn feilen synes å være [CALayer retainCount]: message sent to deallocated instance

Jeg kommer aldri allokering noen lag selv. Før var jeg ikke engang å slette noen visninger eller noe. ble kastet denne feilen på zoom og også på rotere. Hvis jeg sletter objektet før rotasjon og legg det etterpå, det kaster ikke unntaket. Dette er ikke et alternativ for zooming.

Publisert på 15/01/2009 klokken 20:16
kilden bruker
På andre språk...                            


7 svar

stemmer
41

Jeg kan ikke hjelpe deg med den bryter sammen, annet enn fortelle deg å kontrollere og sikre at du ikke utilsiktet autoreleasing en visning eller lag et sted i koden. Jeg har sett simulatoren håndtere timingen av autoreleases annerledes enn på enheten (som oftest når gjengene er involvert).

Utsikten skalering er et problem med UIScrollViewjeg har kjørt inn, though. Under en pinch-zoome hendelse, UIScrollViewvil ta utsikten du har angitt i viewForZoomingInScrollView:representanten metoden og bruke en transformere til det. Denne transformere gir en jevn skalering av visningen uten å plotte den hver ramme. På slutten av zoom operasjonen, representanten metoden scrollViewDidEndZooming:withView:atScale:vil bli kalt, og gi deg en sjanse til å gjøre et mer høykvalitets gjengivelse av ditt syn på den nye skaleringsfaktor. Vanligvis er det foreslått at du har nullstilt transformasjon på visningene for å være CGAffineTransformIdentity, og da har ditt syn manuelt tegne seg på den nye størrelsen skala.

Imidlertid fører dette et problem fordi UIScrollViewsynes ikke å overvåke innholdet visning transform, så på neste zoom det setter trans av innholdet tanke på hva den totale skalaen faktoren er. Siden du har manuelt redrawn ditt syn i siste skaleringsfaktor, forbindelser det skalering, som er det du ser.

Som en midlertidig løsning, jeg bruker en UIView underklasse for innholdet mitt syn med følgende metoder definert:

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

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

hvor previousScale er en flottør forekomst variabel av visningen. Jeg deretter implementere zooming delegat metoden som følger:

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

Ved å gjøre dette, er forvandler sendes til innholdsvisningen justert basert på skalaen der utsikten var siste tegnes på nytt. Når den klype-zooming er gjort, transformasjons blir tilbakestilt til en skala på 1,0 ved å omgå justering i den normale setTransform:metode. Dette synes å gi riktig skalering oppførsel samtidig som du tegner en skarp visning på ferdigstillelse av en zoom.

OPPDATERING (7/23/2010): iPhone OS 3.2 og nyere har endret oppførselen til rulle synspunkter i forhold til zooming. Nå, en UIScrollViewvil respektere identiteten forvandle deg gjelder et innhold visning og bare gi relativ skala faktor i -scrollViewDidEndZooming:withView:atScale:. Derfor koden ovenfor for en UIViewer bare nødvendig for enheter som kjører iPhone OS-versjoner eldre enn 3.2 underklasse.

Svarte 16/01/2009 kl. 19:29
kilden bruker

stemmer
12

Takk til alle tidligere svar, og her er min løsning.
Implementere UIScrollViewDelegate metoder:

- (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 er min underklasse av UIView
  • tmvScrollView - uttaket til UIScrollView
  • satt maximumZoomScale og minimumZoomScale før
  • skape previousScale eksempel variabel og sette verdien til 1.0f

Fungerer for meg perfekt.

BR, Eugene.

Svarte 02/08/2011 kl. 16:33
kilden bruker

stemmer
5

Jeg var bare ute for å nullstille med last til standard zoom skala, fordi når jeg zoomer det er scrollview ha samme zoomskala for neste gang før det blir deallocated.

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

Endret spillet.

Svarte 03/06/2015 kl. 06:53
kilden bruker

stemmer
5

Jeg har en detaljert beskrivelse av hvordan (og hvorfor) UIScrollView zooming fungerer på github.com/andreyvit/ScrollingMadness/ .

(Linken inneholder også en beskrivelse av hvordan du programma zoome UIScrollView, hvordan å etterligne Photo Library-stil paging + zooming + rulling, et eksempel prosjekt og ZoomScrollView klasse som innkapsler noe av zooming magi.)

Sitat:

UIScrollView ikke har en forestilling om en “gjeldende zoomnivå”, fordi hver subview den inneholder kan ha sin egen nåværende zoomnivå. Merk at det ikke er felt i UIScrollView å beholde gjeldende zoomnivå. Men vi vet at noen butikker som zoomnivået, fordi hvis du klype-zoom en subview, tilbake sin transformere til CGAffineTransformIdentity, og deretter klemme igjen, vil du legge merke til at den forrige zoomnivået for subview har blitt restaurert.

Faktisk, hvis du ser på demontering, er det UIView som lagrer sin egen zoom-nivå (inne UIGestureInfo objekt pekt på av _gestureInfo feltet). Den har også et sett med fine udokumenterte metoder som zoomScaleog setZoomScale:animated:. (Mind du, det har også en haug med rotasjonsmessige metoder, kanskje vi får rotasjon gest støtte en dag snart.)

Men hvis vi oppretter en ny UIView bare for zooming og legge til vår virkelige zoomable syn som sitt barn, vil vi alltid starte med zoom-nivå 1,0. Min gjennomføring av programmatisk zooming er basert på dette trikset.

Svarte 07/05/2009 kl. 23:04
kilden bruker

stemmer
3

En ganske pålitelig tilnærming, som passer til iOS 3.2 og 4.0 og senere, er som følger. Du må være forberedt på å levere din skalerbar visning (sjef subview av bla visning) i noen ba skala. Deretter i scrollViewDidEndZooming:du vil fjerne uskarpe skala-transformert versjon av dette synet, og erstatte det med et nytt syn trukket til den nye skalaen.

Du vil trenge:

  • En ivar for å opprettholde den tidligere målestokk; la oss kalle det oldScale

  • En måte å identifisere den skalerbare syn, både for viewForZoomingInScrollView:og etter scrollViewDidEndZooming:; her, jeg kommer til å bruke en tag (999)

  • En metode som skaper skalerbar visning, tags det, og setter den inn på rulle view (her er jeg vil kalle det addNewScalableViewAtScale:). Husk at det må gjøre alt i henhold til skalaen - det størrelser utsikten og dets subviews eller tegning og størrelser rulle visningens contentSize å matche.

  • Konstanter for minimumZoomScale og maximumZoomScale. Dette er nødvendig fordi når vi skifter skalert visning av detaljert større versjon, er systemet kommer til å tenke at dagens målestokk er 1, så vi må lure den inn slik at brukeren kan skalere utsikten ned igjen.

Veldig godt da. Når du oppretter rulle visningen, setter du den skalerbare visning på skalaen 1.0. Dette kan være i viewDidLoad, for eksempel ( sver rulle visning):

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

Så i ditt scrollViewDidEndZooming:du gjør det samme, men kompenserer for endringen i skalaen:

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;
Svarte 12/11/2010 kl. 05:33
kilden bruker

stemmer
2

Merk at løsningen leveres av Brad har ett problem skjønt: hvis du holder programmatisk å zoome inn (la oss si på dobbel trykk hendelse) og la brukeren manuelt (pinch-out) zoome ut, etter en tid forskjellen mellom den sanne skala og omfang UIScrollView sporer vil vokse for stor, så den previousScalevil på et tidspunkt faller ut av float presisjon som til slutt vil resultere i en uforutsigbar oppførsel

Svarte 28/07/2009 kl. 03:43
kilden bruker

stemmer
0

Swift 4. * og Xcode 9.3

Innstilling scrollView zoom skalaen til 0 vil tilbakestille scrollView til det opprinnelige tilstand.

self.scrollView.setZoomScale(0.0, animated: true)
Svarte 29/06/2018 kl. 05:21
kilden bruker

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