В iOS 4.0 почему UIScrollView zoomToRect: animated: не вызывает делегатов scrollViewDidScroll или scrollViewDidZoom во время анимации? - PullRequest
28 голосов
/ 22 октября 2010

Мне нужно внимательно следить за масштабом представления прокрутки, чтобы я мог обновлять элементы представления содержимого (подпредставление, управляющее несколькими CALayers ) в соответствии с анимированным масштабированием представления прокрутки.

На iOS 3.1 все работает как положено, я использую zoomToRect: animated: и scrollViewDidScroll: сообщение UIScrollViewDelegate вызывается многократно, пока анимацияпроисходит , позволяя мне обновлять элементы подпредставления в соответствии с фактическим масштабированием.

Тот же код на iOS 4.0 не демонстрирует такое же поведение.Когда я вызываю zoomToRect: animated: , делегатов ( scrollViewDidScroll: и scrollViewDidZoom ) вызывают только один раз , что делает мои подэлементыдесинхронизируется до окончания анимации.На самом деле, субэлементы сразу же прыгают, а затем увлекаются анимацией масштабирования, пока все не будет в нужном месте.Это как если бы анимация не собирала изменения в подпредставлениях CALayers .

Я пробовал анимировать вручную с помощью блоков анимации, но ситуация та же, никаких прогрессивных обратных вызовов.Я также пробовал KVO, но мне не ясно, как бы я использовал анимацию, управляемую UIScrollView.

Существует ли обходной путь на iOS 4, который позволил бы мне выдвигать значение масштаба для моих подпредставлений как UIScrollView масштаб анимирован?

Ответы [ 4 ]

9 голосов
/ 20 марта 2013

Брутально, но работает.

Определите некоторые свойства:

@property (nonatomic, strong) UIView *zoomedView;    
@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic) CGFloat currentScale;

Сообщите UIScrollView, что UIView будет увеличено:

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
     return self.zoomedView;
}

Зарегистрируйтесь для получения CADisplayLink галочек. Он также запускает Core Animation, поэтому он будет активирован с такими же интервалами:

self.displayLink  = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

Проверьте текущие значения в presentationLayer в zoomedView.

- (void)displayLinkTick
{
    CALayer *zoomedLayer = self.zoomedView.layer.presentationLayer;
    CGFloat scale = zoomedLayer.transform.m11;

    if (scale != self.currentScale) {
         self.currentScale = scale; // update property

         // the scale has changed!
    }
}
1 голос
/ 26 сентября 2011

В IOS 4.0 анимация выполняется ОС - я предполагаю максимально использовать аппаратное ускорение на основе графического процессора.Недостатком этого является то, что становится сложнее анимировать значения, полученные из другого (анимированного) значения.Как и в вашем случае, позиции подпредставлений, которые зависят от уровня масштабирования UIScrollView.Чтобы это произошло, вы должны настроить анимацию подпредставлений так, чтобы она шла параллельно с анимацией масштабирования.Попробуйте что-то вроде:

[UIView animateWithDuration:0.5 delay:0
                    options:UIViewAnimationOptionLayoutSubviews
                 animations:^{
    theScrollView.zoomScale = zoomScale;
    // layout the subviews here
} completion:^(BOOL finished) {}];

Это должно установить свойства кадра подпредставлений из одного и того же контекста анимации, и, следовательно, они должны быть анимированы вместе ОС.ответы на этот вопрос: Как заставить UIScrollView отправлять сообщения scrollViewDidScroll во время анимации

0 голосов
/ 15 ноября 2010

Зарегистрируйтесь для KVO zoomScale свойства UIScrollView после того, как вы позвоните zoomToRect:animated:.

[scrollView addObserver:self
            forKeyPath:@"zoomScale"
               options:(NSKeyValueObservingOptionNew |
                        NSKeyValueObservingOptionOld)
                context:NULL];

Затем реализуйте этот метод:

- (void)observeValueForKeyPath:(NSString *)keyPath
              ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if ([keyPath isEqual:@"zoomScale"]) {
    // use the new zoomScale value stored
    // in the NSKeyValueChangeNewKey change
    // dictionary key  to resize your subviews
    }
    // be sure to call the super implementation
    // if the superclass implements it
    [super observeValueForKeyPath:keyPath
                ofObject:object
                 change:change
                 context:context];
}

Ознакомьтесь с документацией КВО .

0 голосов
/ 12 ноября 2010

Возможно ли обновить все подпредставления в блоке анимации (или begin / commitAnimation)?Что-то вроде:

[self zoomToRect:zoomRect animated:YES];
[UIView animateWithDuration:1.0
    animations:^ {
        // change your subviews
    }
];
...