Fade in/out Содержимое UIScrollView, например Mobile Safari, на вкладке

ПРИМЕЧАНИЕ. Я добавил новое решение в ответ UPDATE ниже.

Я пытаюсь воссоздать эффекты, которые мы видели на вкладке Mobile Safari на iPhone/iPod touch.

В принципе, это UIScrollView, который содержит 4 повторно используемых UIView (действующий как кольцевой буфер) и прокручивается по горизонтали. При прокрутке прозрачность UIView будет плавно входить/выходить со смещением.

В настоящее время я выполняю всю грязную работу в - (void)scrollViewDidScroll:(UIScrollView *)scrollView. Например, получение contentOffset из UIScrollView, определение страницы, вычисление дельта между contentOffset и каждой позицией UIView, а также принятие/установка альфа-значения каждого UIView в момент вызова scrollViewDidScroll:.

И это работает, производительность в порядке, все работает гладко, но единственная проблема - слишком много вычислений.

Я пробовал UIView beginAnimations: и commitAnimations:, но это бесполезно в scrollViewDidScroll:, так как 1) новое значение альфа все равно должно быть вычислено мною, а 2) scrollViewDidScroll: сохраняется при прокрутке, это бессмысленно сделайте анимацию здесь. Есть ли способ переписать эту часть с Core Animation? Поэтому мне не нужно делать математику самостоятельно по альфа-значению каждого UIView, вместо этого я могу оставить целые работы в Core Animation.

Ответ 1

UPDATE

Я придумал другой способ обновить альфа-значение каждой страницы. При создании представления содержимого я использую KVO для addObserver с UIScrollView contentOffset:

[self.scrollView addObserver:[self.contentViews objectAtIndex:i] 
                  forKeyPath:@"contentOffset" 
                     options:NSKeyValueObservingOptionNew
                     context:@selector(updateAlpha:)];

Чтобы каждый из моих ContentViews получал сообщение при изменении contentOffset:

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context {
    [self performSelector:(SEL)context withObject:change];
}

И мои contentViews могут выполнять вычисления и анимировать сами при прокрутке:

- (void)updateAlpha:(NSDictionary *)change {
    CGFloat offset = [[change objectForKey:NSKeyValueChangeNewKey] CGPointValue].x;
    CGFloat origin = [self frame].origin.x;
    CGFloat delta = fabs(origin - offset);

    [UIView beginAnimations:@"Fading" context:nil];
    if (delta < [self frame].size.width) {
        self.alpha = 1 - delta/self.frame.size.width*0.7;
    } else {
        self.alpha = 0.3;
    }
    [UIView commitAnimations];
}

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

Надеюсь, что эта помощь поможет тем, кто хочет сделать то же самое.

Ответ 2

Как вы заметили, как часто вызывается scrollViewDidScroll: UIScrollView не просто запускает и забывает переход на Core Animation: он вручную перемещает границы в соответствии с касаниями, ускорением и т.д. Нет простого способа изменить это.

Однако, если вас забивают события прокрутки, вы можете попробовать трюк, подобный следующему:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970];
    if (timestamp - _savedTimestamp) < 0.1)
        return;
    _savedTimestamp = timestamp;

    // do the rest of your work here
}

Н