2010-07-22 3 views
5

У меня есть UIView внутри UIScrollView. Когда изменяется масштаб UIScrollView, я хочу перерисовать весь UIView на новом уровне масштабирования.Перерисовывать содержимое UIScrollView после каждого масштабирования

В прошивкой < 3.2, я делал это путем изменения размера UIView внутри UIScrollView, чтобы сделать его новый размер, а затем установить преобразование обратно в идентичности, так что он не будет пытаться изменить его дальше. Однако при iOS> = 3.2 изменение идентификатора также изменяет свойство zoomScale UIScrollView.

Результатом является то, что всякий раз, когда я масштабирую (скажем, 2x), я настраиваю встроенный UIView на соответствующий размер и перерисовываю его. Однако теперь (с тех пор, как я сбросил преобразование в Identity), UIScrollView снова думает об этом в zoomScale 1, а не zoomScale 2. Поэтому, если у меня есть maxXoomScale, установленный на 2, он все равно попытается увеличить масштаб, что неверно.

Я думал об использовании CATiledLayer, но я не думаю, что этого достаточно для меня, так как я хочу перерисовывать после каждого масштабирования, а не только с определенными порогами масштабирования, как это делается.

Кто-нибудь знает, как сделать правильную перерисовку UIView при масштабировании?

ответ

15

Том,

Ваш вопрос немного старый, но я придумал решение для этого, поэтому я решил, что я положил в ответ в случае, если это помогает вам или кому-либо еще. Основной трюк состоит в том, чтобы сбросить вид прокрутки zoomScale до 1, а затем отрегулировать minimumZoomScale и maximumZoomScale, чтобы пользователь мог увеличивать и уменьшать масштаб, как ожидалось.

В моей реализации я подклассифицировал UIScrollView и назначил его своим делегатом. В моем подклассе я реализую два метода делегата, которые вам нужны для масштабирования (показано ниже). contentView - это свойство, которое я добавил в мой подкласс UIScrollView, чтобы дать ему представление, которое фактически отображает содержимое.

Итак, мой метод инициализации выглядит примерно так (kMinimumZoomScale и kMaximumZoomScale являются #define «s в верхней части класса):

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

Тогда я реализовать стандартные UIScrollView методы делегата для масштабирования. Мой класс ContentView имеет свойство zoomScale, которое сообщает ему, какой масштаб использовать для отображения его содержимого. Он использует это в своем методе drawRect для изменения размера содержимого по мере необходимости.

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

Большое вам спасибо за ваше решение! Это решает [мой вопрос] (http://stackoverflow.com/questions/3970988/how-to-draw-on-a-non-transformed-context-while-zoomed-in-a-catiledlayer). Не могли бы вы оставить ссылку на свой ответ там, чтобы я мог дать вам должное ответить на него? – TinkerTank

+0

Если этот метод используется для увеличения CATiledLayer, кеш-фрагмент необходимо очистить до вызова setNeedsDisplay. Доступно решение для очистки CATiledLayerCache [здесь] (http: // stackoverflow.com/questions/1274680/clear-catiledlayers-cache-when-change-images) – TinkerTank

+0

Не могли бы вы объяснить свойство contentSize и то, как он будет установлен и что это на самом деле. Спасибо – BDGapps

0

В моем случае у меня есть вид изображения и в верхней части изображения. У меня есть несколько других изображений. Это реализация, которую я придумал и прекрасно работает:

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

} 
Смежные вопросы