Come faccio a reimpostare dopo uno zoom UIScrollView?

voti
15

Ho un grafico in fase di elaborazione all'interno di una UIScrollView. E 'una grande UIViewutilizzando una sottoclasse personalizzata di CATiledLayercome il suo livello.

Quando io lo zoom in e fuori del UIScrollView, voglio il grafico di ridimensionare in modo dinamico, come invece accade quando torno il grafico da viewForZoomingInScrollView. Tuttavia, il grafico si ridisegna al nuovo livello di zoom, e voglio ripristinare la scala trasformazione per 1x1 in modo che la prossima volta che l'utente ingrandisce, il trasformare inizia dalla vista corrente. Se a reimpostare la trasformazione di identità in scrollViewDidEndZooming, funziona nel simulatore, ma genera EXC_BAD_ACCSESsul dispositivo.

Questo non ha nemmeno risolve il problema del tutto sul simulatore sia, perché la prossima volta che l'utente ingrandisce, la trasformata di reset per sé a qualsiasi livello di zoom è stato a, e così sembra che, se mi è stato zoomato a 2x, per esempio, è improvvisamente a 4x. Quando ho finito lo zoom, finisce alla scala corretta, ma il vero e proprio atto di zoom sembra male.

Quindi prima: come faccio a permettere il grafico per ridisegnare se stessa alla tabella standard di 1x1 dopo lo zoom, e come posso avere uno zoom liscia per tutto?

Edit: Nuove scoperte L'errore sembra essere [CALayer retainCount]: message sent to deallocated instance

Non sono mai deallocando eventuali strati me stesso. Prima, non ero nemmeno l'eliminazione di eventuali pareri o nulla. Questo errore è stato stato gettato su zoom e anche sulla Ruota. Se elimino l'oggetto prima della rotazione e ri-aggiungerlo dopo, non gettare l'eccezione. Questa non è un'opzione per lo zoom.

È pubblicato 15/01/2009 alle 21:16
fonte dall'utente
In altre lingue...                            


7 risposte

voti
41

Non posso aiutare con il fragore, diverso da dire per controllare e assicurarsi che non sta involontariamente autoreleasing una vista o un livello da qualche parte all'interno del codice. Ho visto il simulatore gestire i tempi di autoreleases diverso rispetto al dispositivo (più spesso quando sono coinvolti fili).

La scala vista è un problema con UIScrollViewche ho incontrato, però. Nel corso di un evento di pinch-zoom, UIScrollViewvi porterà la vista specificata nel viewForZoomingInScrollView:metodo delegato e applicare una trasformazione ad essa. Questa trasformazione fornisce una superficie liscia scala della vista senza dover ridisegnare ogni fotogramma. Al termine delle operazioni di zoom, il vostro metodo delegato scrollViewDidEndZooming:withView:atScale:sarà chiamato e vi darà la possibilità di fare una resa più alta qualità della visualizzazione presso il nuovo fattore di scala. In generale, è suggerito che si reimpostare la trasformazione su l'immagine per essere CGAffineTransformIdentitye quindi avere la vostra vista stessa ridisegnare manualmente la nuova scala di calibro.

Tuttavia, questo causa un problema perché UIScrollViewnon sembra per monitorare la visualizzazione di contenuti trasforma, così la prossima operazione di zoom si imposta la trasformazione della vista dei contenuti a tutto ciò che il fattore di scala è. Dal momento che hai ridisegnato manualmente la vista all'ultimo fattore di scala, si aggrava il ridimensionamento, che è quello che si sta vedendo.

Per aggirare il problema, io uso una sottoclasse UIView per il mio punto di vista dei contenuti con i seguenti metodi definiti:

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

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

dove previousScale è una variabile di istanza flottante della vista. Ho quindi implementare il metodo delegato zoom come segue:

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

In questo modo, le trasformazioni inviati alla vista dei contenuti sono regolati in base al scala a cui la vista era ultima ridisegnato. Quando il pinch-zoom è fatto, la trasformazione viene reimpostato su una scala da 1.0 bypassando la regolazione nel normale setTransform:metodo. Questo sembra fornire il comportamento della scala corretta mentre ti permette di disegnare una visione nitida al completamento di uno zoom.

UPDATE (7/23/2010): iPhone OS 3.2 e superiori hanno cambiato il comportamento di punti di vista di scorrimento per quanto riguarda lo zoom. Ora, un UIScrollViewrispetterà l'identità Transform si applica a una visione di contenuti e di fornire solo il fattore di scala relativa -scrollViewDidEndZooming:withView:atScale:. Pertanto, il codice qui sopra per una UIViewsottoclasse è necessaria solo per i dispositivi che eseguono versioni iPhone OS di età superiore a 3.2.

Risposto il 16/01/2009 a 20:29
fonte dall'utente

voti
12

Grazie a tutte le risposte precedenti, e qui è la mia soluzione.
Implementare UIScrollViewDelegate metodi:

- (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 è il mio sottoclasse di UIView
  • tmvScrollView - presa a UIScrollView
  • set maximumZoomScale e minimumZoomScale prima
  • creare previousScale variabile istanza e impostare il valore 1.0f

Lavora per me perfettamente.

BR, Eugene.

Risposto il 02/08/2011 a 17:33
fonte dall'utente

voti
5

Ho una discussione dettagliata di come (e perché) UIScrollView zoom funziona a github.com/andreyvit/ScrollingMadness/ .

(Il link contiene anche una descrizione di come lo zoom di programmazione UIScrollView, come emulare Foto in stile Libreria paging + zoom + scorrimento, un esempio di progetto e la classe che incapsula ZoomScrollView po 'della magia zoom.)

Citazione:

UIScrollView non ha una nozione di un “livello di zoom corrente”, perché ogni visualizzazione secondaria in esso contenuti possono avere un proprio livello di zoom corrente. Si noti che non v'è alcun campo in UIScrollView per mantenere il livello di zoom corrente. Tuttavia sappiamo che qualcuno memorizza quel livello di zoom, perché se si pinch-zoom una visualizzazione secondaria, quindi reimpostare la sua trasformazione per CGAffineTransformIdentity, e poi un pizzico di nuovo, si noterà che il precedente livello di zoom della visualizzazione secondaria è stata restaurata.

In effetti, se si guarda al disassemblaggio, è UIView che memorizza il proprio livello di zoom (all'interno oggetto UIGestureInfo puntato dal campo _gestureInfo). Essa ha anche un insieme di metodi non documentati molto comode come zoomScalee setZoomScale:animated:. (Si badi bene, ma ha anche un sacco di metodi di rotazione relativi, forse stiamo ottenendo gesto rotazione supporta un giorno presto.)

Tuttavia, se creiamo un nuovo UIView solo per lo zoom e aggiungiamo la nostra vera e propria vista stradale come suo figlio, ci sarà sempre iniziare con livello di zoom 1.0. La mia implementazione di zoom programmatico si basa su questo trucco.

Risposto il 08/05/2009 a 00:04
fonte dall'utente

voti
4

Stavo solo cercando di ripristinare il carico da scala zoom predefinito, perché quando ho Zoommala, ScrollView sta avendo stessa scala di zoom per la prossima volta fino a quando non viene deallocato.

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

Cambiato il gioco.

Risposto il 03/06/2015 a 06:53
fonte dall'utente

voti
3

Un approccio abbastanza affidabile, adeguato a iOS 3.2 e 4.0 e versioni successive, è la seguente. È necessario essere preparati per alimentare la visualizzazione scalabile (il capo visualizzazione secondaria della vista di scorrimento) in qualsiasi scala richiesto. Poi, nel scrollViewDidEndZooming:si rimuoverà la versione sfocata scala-trasformata di questa visione e sostituirla con una nuova vista disegnato per la nuova scala.

Avrai bisogno:

  • Un Ivar per mantenere la scala precedente; chiamiamolo oldScale

  • Un modo di identificare vista scalabile, sia per viewForZoomingInScrollView:e scrollViewDidEndZooming:; qui, ho intenzione di applicare un tag (999)

  • Un metodo che crea la vista scalabile, tag, e lo inserisce nella vista di scorrimento (ecco lo chiamerò addNewScalableViewAtScale:). Ricordate, deve fare tutto secondo la scala - Le dimensioni di visualizzazione e le sue subviews o disegno, e dimensioni contentSize della vista di scorrimento per abbinare.

  • Costanti per la minimumZoomScale e maximumZoomScale. Questi sono necessari perché quando si sostituisce la vista in scala dalla versione dettagliata più grande, il sistema sta andando a pensare che la scala corrente è 1, quindi dobbiamo ingannare in che permette all'utente di scalare la vista verso il basso.

Molto bene allora. Quando si crea la vista di scorrimento, si inserisce la visualizzazione scalabile a scala 1.0. Questo potrebbe essere nel vostro viewDidLoad, per esempio ( svè la vista di scorrimento):

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

Poi, nel tuo scrollViewDidEndZooming:si fa la stessa cosa, ma per compensare il cambiamento di scala:

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;
Risposto il 12/11/2010 a 06:33
fonte dall'utente

voti
2

Si noti che la soluzione fornita da Brad ha un problema, però: se si mantiene a livello di codice lo zoom (diciamo il doppio evento rubinetto) e lasciate utente manualmente (pinch-out) zoom out, dopo qualche tempo la differenza tra la reale portata e la scala UIScrollView sta rintracciando crescerà troppo grande, quindi la previousScalevolontà ad un certo punto di caduta di precisione del galleggiante che finirà per determinare un comportamento imprevedibile

Risposto il 28/07/2009 a 04:43
fonte dall'utente

voti
0

Swift 4. * e Xcode 9.3

Impostazione ScrollView scala di zoom a 0 sarà reimpostare la ScrollView al suo stato iniziale.

self.scrollView.setZoomScale(0.0, animated: true)
Risposto il 29/06/2018 a 05:21
fonte dall'utente

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