13

注意:我在下面的更新答案中添加了我的新解决方案。

我尝试重现我们在 iPhone/iPod touch 上的 Mobile Safari 选项卡中看到的效果。

基本上,它是一个 UIScrollView,它拥有 4 个可重用的 UIView(充当环形缓冲区),并水平滚动。滚动时,UIView 的不透明度将通过偏移无缝淡入/淡出。

目前,我在- (void)scrollViewDidScroll:(UIScrollView *)scrollView. 比如从 UIScrollView 中获取 contentOffset,确定分页,计算 contentOffset 和每个 UIView 位置之间的 delta,决定/设置每个 UIView 在scrollViewDidScroll:被调用时的 alpha 值。

它可以工作,性能还可以,一切运行顺利,但唯一的问题是计算量太大。

我试过UIView的beginAnimations:and commitAnimations:,但是在里面没用scrollViewDidScroll:,因为1)新的alpha值还是要自己计算,2)scrollViewDidScroll:滚动的时候一直调用,这里做动画没意义。有没有办法用 Core Animation 重写这部分?所以我不必自己计算每个 UIView 的 alpha 值,相反,我可以将整个作品留给 Core Animation。

4

2 回答 2

26

更新

我想出了另一种方法来更新每个页面的 alpha 值。创建内容视图时,我使用 KVO 添加带有 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];
}

当然,当您从 superview 中删除内容视图时,您需要删除观察者,并在创建新的内容视图时再次添加它们。

希望这对那些想要做同样事情的人有所帮助。

于 2009-05-24T14:36:50.693 回答
2

正如您从 scrollViewDidScroll: 调用频率中所注意到的那样,UIScrollView 不会简单地触发并忘记核心动画转换:它会根据触摸、加速度等手动移动边界。没有直接的方法可以改变这一点。

但是,如果您被滚动事件淹没,您可以尝试以下技巧:

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

    // do the rest of your work here
}

H

于 2009-05-18T16:01:09.697 回答