2010-07-22 1 views
5

Possiedo un UIView all'interno di uno UIScrollView. Ogni volta che lo zoom UIScrollView cambia, voglio ridisegnare l'intero UIView al nuovo livello di zoom.Ridisegnare i contenuti di UIScrollView dopo ogni zoom

In iOS 3.2 <, stavo facendo questo ridimensionando la UIView all'interno del UIScrollView per rendere la nuova dimensione, e quindi impostando la trasformazione torna a Identità, in modo che non avrebbe cercato di ridimensionare ulteriormente. Tuttavia, con iOS> = 3.2, la modifica dell'identità modifica anche la proprietà zoomScale di UIScrollView.

Il risultato è che ogni volta che eseguo lo zoom (ad esempio 2x), aggiusto la dimensione UIView incorporata come appropriata e la ridisegna. Comunque ora (dato che ho ripristinato la trasformazione in Identity), lo UIScrollView pensa che sia ancora una volta su zoomScale 1, invece che su ZoomScale 2. Quindi, se ho il mio maxZoomScale impostato a 2, tenterà comunque di ingrandire ulteriormente, che è sbagliato.

Ho pensato di utilizzare lo CATiledLayer, ma non penso che questo sia sufficiente per me, dal momento che voglio ridisegnare dopo ogni zoom, non solo a determinate soglie di zoom come si tenta di fare.

Qualcuno sa come eseguire il corretto ridisegno dello UIView su uno zoom?

risposta

15

Tom,

La tua domanda è un po 'vecchio, ma mi si avvicinò con una soluzione per questo, così ho pensato che avevo messo in una risposta nel caso in cui tu o chiunque altro aiuta. Il trucco di base consiste nel reimpostare la vista a scorrimento su zoomScale su 1, quindi regolare minimumZoomScale e maximumZoomScale in modo che l'utente possa ancora ingrandire e rimpicciolire come previsto.

Nella mia implementazione, ho creato una sottoclasse di UIScrollView e l'ho impostato come suo delegato. Nella mia sottoclasse, implemento i due metodi delegati necessari per lo zoom (mostrato sotto). contentView è una proprietà che ho aggiunto alla sottoclasse UIScrollView che per dargli la vista che visualizza effettivamente il contenuto.

Quindi, il mio metodo init simile a questa (kMinimumZoomScale e kMaximumZoomScale sono #define 's al vertice della classe):

- (id)initWithFrame:(CGRect)frame { 
    if (self = [super initWithFrame:frame]) { 
     self.autoresizesSubviews = YES; 
     self.showsVerticalScrollIndicator = YES; 
     self.showsHorizontalScrollIndicator = NO; 
     self.bouncesZoom = YES; 
     self.alwaysBounceVertical = YES; 
     self.delegate = self; 

     self.minimumZoomScale = kMinimumZoomScale; 
     self.maximumZoomScale = kMaximumZoomScale; 
    } 

    return self; 
} 

Poi ho implementano le UIScrollView metodi delegato standard di per lo zoom. La mia classe ContentView ha una proprietà chiamata zoomScale che indica quale scala utilizzare per visualizzare il suo contenuto. Lo usa nel suo metodo drawRect per ridimensionare il contenuto come appropriato.

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)aScrollView { 
    return contentView; 
} 


- (void)scrollViewDidEndZooming:(UIScrollView *)aScrollView withView:(UIView *)view atScale:(float)scale { 
    CGFloat oldZoomScale = contentView.zoomScale; 
    CGSize size = self.bounds.size; 

    // Figure out where the scroll view was centered so that we can 
    // fix up its offset after adjusting the scaling 
    CGPoint contentCenter = self.contentOffset; 
    contentCenter.x += size.width/(oldZoomScale * scale)/2; 
    contentCenter.y += size.height/(oldZoomScale * scale)/2; 

    CGFloat newZoomScale = scale * oldZoomScale; 
    newZoomScale = MAX(newZoomScale, kMinimumZoomscale); 
    newZoomScale = MIN(newZoomScale, kMaximumZoomscale); 

    // Set the scroll view's zoom scale back to 1 and adjust its minimum and maximum 
    // to allow the expected amount of zooming. 
    self.zoomScale = 1.0; 
    self.minimumZoomScale = kMinimumZoomScale/newZoomScale; 
    self.maximumZoomScale = kMaximumZoomScale/newZoomScale; 

    // Tell the contentView about its new scale. My contentView.zoomScale setter method 
    // calls setNeedsDisplay, but you could also call it here 
    contentView.zoomScale = newZoomScale; 

    // My ContentView class overrides sizeThatFits to give its expected size with 
    // zoomScale taken into account 
    CGRect newContentSize = [contentView sizeThatFits]; 

    // update the content view's frame and the scroll view's contentSize with the new size 
    contentView.frame = CGRectMake(0, 0, newContentSize.width, newContentSize.height); 
    self.contentSize = newContentSize; 

    // Figure out the new contentOffset so that the contentView doesn't appear to move 
    CGPoint newContentOffset = CGPointMake(contentCenter.x - size.width/newZoomScale/2, 
              contentCenter.y - size.height/newZoomScale/2); 
    newContentOffset.x = MIN(newContentOffset.x, newContentSize.width - size.width); 
    newContentOffset.x = MAX(0, newContentOffset.x); 
    newContentOffset.y = MIN(newContentOffset.y, newContentSize.height - .size.height); 
    newContentOffset.y = MAX(0, newContentOffset.y); 
    [self setContentOffset:newContentOffset animated:NO]; 
} 
+0

Grazie mille per la soluzione! Questo risolve [la mia domanda] (http://stackoverflow.com/questions/3970988/how-to-draw-on-a-non-transformed-context-while-zoomed-in-a-catiledlayer). Potresti lasciare un link alla tua risposta lì, quindi posso darti il ​​giusto credito per rispondergli? – TinkerTank

+0

Se questo metodo viene utilizzato per ingrandire un CATiledLayer, il tile-cache deve essere cancellato prima di chiamare setNeedsDisplay. Una soluzione per la rimozione di CATiledLayerCache è disponibile [qui] (http: // StackOverflow.it/questions/1274680/clear-catiledlayers-cache-when-changing-images) – TinkerTank

+0

puoi spiegare la proprietà di contentSize e come viene impostata e cosa è effettivamente. Grazie – BDGapps

0

Nel mio caso, io ho una visione delle immagini e sulla parte superiore della vista dell'immagine ho diversi altri imageviews. Questa è l'implementazione che mi è venuta in mente e funziona perfettamente:

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(double)scale{ 
    NSLog(@"finished zooming"); 

    NSLog(@"position x :%f",pin1.frame.origin.x); 
    NSLog(@"position y :%f",pin1.frame.origin.y); 


    CGRect frame = pin1.frame; 
    frame.origin.x = pin1.frame.origin.x * scale; 
    frame.origin.y = pin1.frame.origin.y * scale; 
    pin1.frame = frame; 

    NSLog(@"position x new :%f",pin1.frame.origin.x); 
    NSLog(@"position y new:%f",pin1.frame.origin.y); 

}