Cum resetez după un zoom UIScrollView?

voturi
15

Am un grafic fiind tras în interiorul unui UIScrollView. Este o mare UIViewfolosind o subclasă personalizat de CATiledLayerdrept stratului său.

Când m - am mări și în afara UIScrollView, vreau grafic pentru a redimensiona dinamic așa cum o face atunci când mă întorc de la graficul viewForZoomingInScrollView. Cu toate acestea, graficul se redesenează la noul nivel de zoom, și vreau să resetați scara transformatei 1x1 , astfel încât data viitoare când utilizatorul face zoom, transformare pornește de la vizualizarea curentă. Dacă resetez transformatei identității în scrollViewDidEndZooming, funcționează în simulator, dar aruncă o EXC_BAD_ACCSESpe dispozitiv.

Acest lucru nu rezolvă problema, chiar în întregime pe simulator, fie, pentru că data viitoare când utilizatorul face zoom, de transformare în sine resetează la orice nivel de mărire a fost la, și așa se pare că, dacă am fost mărită la 2x, de exemplu, este brusc la 4x. Când am terminat zoom-ul, se termină până la scara corectă, dar actul real al zoom-ului arată rău.

Deci, în primul rând: Cum pot permite grafic pentru a se aspira la scara standard 1x1 după zoom, și cum am un zoom, lin?

Editare: Noile descoperiri Eroarea pare a fi „ [CALayer retainCount]: message sent to deallocated instance

Eu nu dealocarea nici straturi mine. Înainte, nu am fost chiar și ștergerea orice opinii sau ceva. Această eroare a fost a fost aruncat pe zoom și, de asemenea, pe Rotate. Dacă am șterge obiectul înainte de rotație și adăugați din nou după aceea, nu arunca excepție. Aceasta nu este o opțiune pentru zoom.

Întrebat 15/01/2009 la 21:16
sursa de către utilizator
În alte limbi...                            


7 răspunsuri

voturi
41

Nu te pot ajuta cu spărgeau, altele decât să vă spun pentru a verifica și asigurați-vă că nu sunt autoreleasing în mod neintenționat o vedere sau strat undeva în codul dumneavoastră. Am văzut simulatorul ocupa calendarul de autoreleases diferit față de dispozitivul (cel mai adesea atunci când sunt implicate fire).

Punctul de vedere al scalarea este o problemă cu care UIScrollViewam rula în, totuși. În timpul unui eveniment de zoom pinch, UIScrollViewva avea vizualizarea ați specificat în viewForZoomingInScrollView:metoda delegat și aplică o transformare la ea. Această transformare oferă o scalare lină a vizualizării fără a fi nevoie să - l redesena fiecare cadru. La sfârșitul operației de zoom, metoda delegat scrollViewDidEndZooming:withView:atScale:va fi numit și vă va oferi o șansă de a face o redare mai mult de vedere de calitate ridicată la noul factor de scală. În general, este sugerat să resetați transformat pe punctul dumneavoastră de vedere să fie CGAffineTransformIdentityși apoi au afișarea în sine redesena manual la noua scara dimensiune.

Cu toate acestea, acest lucru cauzează o problemă , deoarece UIScrollViewnu pare să monitorizeze vizualizarea conținutului transforma, astfel încât la următoarea operație de zoom seteaza Transformata vizualizarea conținutului la orice factor de scală globală este. Din moment ce ai redesenat manual vedere la ultimul factor baremului, compușii scalarea, care este ceea ce vezi.

Ca soluție alternativă, folosesc o subclasă UIView pentru opinia noastră de conținut, cu următoarele metode definite:

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

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

în cazul în care previousScale este o instanță variabilă float a vizualizării. apoi am pune în aplicare metoda delegat zoom după cum urmează:

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

Prin aceasta, transformatelor trimise la vizualizarea conținutului sunt ajustate în funcție de scara la care punctul de vedere a fost ultima redesenata. Când pinch-zoomingul se face, de transformare este resetat la o scară de la 1.0 prin ocolirea ajustarea în normale setTransform:metodei. Acest lucru pare să asigure comportamentul corect de scalare în timp ce permițându - vă să atragă o vedere clară la finalizarea unui zoom.

UPDATE (7/23/2010): iPhone OS 3.2 și mai sus , s- au schimbat comportamentul de opinii de defilare în ceea ce privește la zoom. Acum, o UIScrollViewva respecta identitatea transformatei aplica la o vizualizare de conținut și să ofere doar factorul de scara relativă -scrollViewDidEndZooming:withView:atScale:. Prin urmare, codul de mai sus pentru o UIViewsubclasa este necesară numai pentru dispozitive care rulează versiuni de iPhone OS mai vechi de 3.2.

Publicat 16/01/2009 la 20:29
sursa de către utilizator

voturi
12

Datorită toate răspunsurile anterioare, și aici este soluția mea.
Punerea în aplicare a UIScrollViewDelegate metode:

- (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 este subclasă mea de UIView
  • tmvScrollView - ieșire la UIScrollView
  • set maximumZoomScale și minimumZoomScale înainte
  • a crea previousScale variabilă instanță și setați valoarea la 1.0f

Funcționează perfect pentru mine.

BR, Eugene.

Publicat 02/08/2011 la 17:33
sursa de către utilizator

voturi
5

Am o discuție detaliată a modului în care (și de ce) funcționează UIScrollView zoom - ului la github.com/andreyvit/ScrollingMadness/ .

(Link-ul conține, de asemenea, o descriere a modului de a mări programatic UIScrollView, cum să imite Fototecă stil de paginare + zoom + defilare, un proiect de exemplu și clasa ZoomScrollView care încapsulează o parte din magia zoom.)

Citat:

UIScrollView nu are o noțiune de „un nivel de zoom curent“, pentru că fiecare subview conține poate avea propriul nivelul actual de zoom. Rețineți că nu există nici un câmp în UIScrollView pentru a menține nivelul de zoom curent. Cu toate acestea știm că cineva stochează acel nivel de zoom, pentru că dacă prindeți-zoom un subview, apoi resetați transformata ei la CGAffineTransformIdentity, și apoi prindeți din nou, veți observa că nivelul de zoom anterior al subview a fost restaurată.

Într - adevăr, dacă te uiți la dezasamblarea, este UIView care stochează propriul său nivel de zoom ( în interiorul obiectului UIGestureInfo indicat de către câmpul _gestureInfo). Ea are , de asemenea , un set de metode , cum ar fi frumos nedocumentate zoomScaleși setZoomScale:animated:. (Țineți minte, are , de asemenea , o grămadă de metode legate de rotație, poate că ne apropiem de rotație gest susține într- o zi în curând.)

Cu toate acestea, dacă vom crea un nou UIView doar pentru zoom și adăugați punctul nostru de vedere real, zoomable ca copilul ei, vom începe întotdeauna cu nivelul de zoom 1.0. implementarea mea a zoom-ului programatic se bazează pe acest truc.

Publicat 08/05/2009 la 00:04
sursa de către utilizator

voturi
4

Am fost doar în căutarea de a reseta la încărcare la valorile implicite scala de zoom, pentru că atunci când am zoom, scrollview are aceeași scală de mărire pentru data viitoare, până când acesta devine deallocated.

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

A schimbat jocul.

Publicat 03/06/2015 la 06:53
sursa de către utilizator

voturi
3

O abordare destul de fiabile, adecvate pentru iOS 3.2 și 4.0 și mai târziu, este după cum urmează. Trebuie să fii pregătit să furnizeze afișarea scalabilă (The subview șef vizualizarea de parcurgere) , în orice scară solicitată. Apoi , în scrollViewDidEndZooming:tine va elimina versiunea neclară transformat-scară de la acest punct de vedere și să o înlocuiască cu o nouă vizualizare trase la noua scara.

Vei avea nevoie:

  • Un Ivar pentru menținerea scalei anterioare; Să-l numim oldScale

  • O modalitate de a identifica punctul de vedere scalabil, atât pentru cât viewForZoomingInScrollView:și pentru scrollViewDidEndZooming:; aici, am de gând să aplice o etichetă (999)

  • O metodă care creează vederea scalabil, etichetează - l și - l introduce în vizualizarea de defilare (aici este o voi suna addNewScalableViewAtScale:). Amintiți - vă, trebuie să facă totul în funcție de scara - aceasta dimensiuni vizualizarea și subviews sau desen sale și dimensiunile contentSize ecranul de parcurgere a lui pentru a se potrivi.

  • Constante pentru minimumZoomScale și maximumZoomScale. Acestea sunt necesare pentru că atunci când vom înlocui vizualizarea scalată de versiunea detaliată mai mare, sistemul va crede că scara actuală este de 1, așa că trebuie să-l pacaleasca care permite utilizatorului să scaleze vizualizarea înapoi în jos.

Foarte bine atunci. Când creați vizualizarea defilare, introduceți vizualizarea scalabil la scara 1.0. Acest lucru ar putea fi în dumneavoastră viewDidLoad, de exemplu ( sveste punctul de vedere parcurgere):

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

Apoi , în dumneavoastră scrollViewDidEndZooming:vă face același lucru, dar compensează pentru schimbarea la scară:

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;
Publicat 12/11/2010 la 06:33
sursa de către utilizator

voturi
2

Rețineți că soluția oferită de Brad are o singură problemă , totuși: dacă vă păstrați programatic mărire (să spunem despre evenimentul atingeți de două ori) și permiteți utilizatorului manual (pinch-out) zoom out, după ceva timp diferența dintre scala adevărată și scara UIScrollView este de urmărire va crește prea mare, astfel încât previousScalevoința la un moment dat să cadă din precizie float, care va duce în cele din urmă într - un comportament imprevizibil

Publicat 28/07/2009 la 04:43
sursa de către utilizator

voturi
0

Swift 4. * și Xcode 9.3

Setarea scrollView scala de zoom la 0 va reseta scrollView la starea sa inițială.

self.scrollView.setZoomScale(0.0, animated: true)
Publicat 29/06/2018 la 05:21
sursa de către utilizator

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