TwitterCover实现及优化

现在很多App都有一个实现首页下拉图片变大变模糊效果的动画,这个最早是Twitter实现的,确实是很有创意的动画。TwitterCover就是实现这个动画的开源库,用起来很方便,但是有个缺点就是内存消耗很大。

TwitterCover

github地址
它的源码非常简单,思路很清晰。
为了方便调用,对原有代码没有侵入性:

  • UIScrollerView的category,有个imageView属性。
  • 监控contentOffset,根据contentOffset.y可以知道上拉下滑的距离,从而改变imageView的大小及image。

图片变模糊变大的方法:

  • 用模糊函数对原image处理,生成20张图片,然后根据contentOffset.y重新setImage。
//生成20张图片
- (void)prepareForBlurImages
{
    CGFloat factor = 0.1;
    [blurImages_ addObject:self.image];
    for (NSUInteger i = 0; i < 20; i++) {
        [blurImages_ addObject:[self.image boxblurImageWithBlur:factor]];
        factor+=0.04;
    }
}

//根据contentOffset.y重新setImage和给imageView设置height
- (void)layoutSubviews
{
    [super layoutSubviews];
    if (self.scrollView.contentOffset.y < 0) {
        CGFloat offset = -self.scrollView.contentOffset.y;
        topView.frame = CGRectMake(0, -offset, 320, topView.bounds.size.height);

        self.frame = CGRectMake(-offset,-offset + topView.bounds.size.height, 320+ offset * 2, CHTwitterCoverViewHeight + offset);
        NSInteger index = offset / 10;
        if (index < 0) {
            index = 0;
        }
        else if(index >= blurImages_.count) {
            index = blurImages_.count - 1;
        }
        UIImage *image = blurImages_[index];
        if (self.image != image) {
            [super setImage:image];
        }
        
    }
    else {
        topView.frame = CGRectMake(0, 0, 320, topView.bounds.size.height);

        self.frame = CGRectMake(0,topView.bounds.size.height, 320, CHTwitterCoverViewHeight);
        UIImage *image = blurImages_[0];

        if (self.image != image) {
            [super setImage:image];
        }
    }
}

优点: 代码侵入性小,用起来方便。
缺点: 生成了20张image,很耗内存。

我的实现

其实为了实现image背景变大变模糊完全没有必要生成20张图片。直接做动画就行了,虽然这样不会变模糊,但是效果还是很不错的。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (self.scrollView.contentOffset.y < 0) {
        CGFloat offset = fabs(self.scrollView.contentOffset.y);
        CGFloat height = _viewFrame.size.height;
        CGFloat ratio = (height + 2 * offset) / height;
        
        self.transform = CGAffineTransformScale(CGAffineTransformMakeTranslation(0, -offset), ratio, ratio);
    }
}

想法

其实动画的实现都是次要的,关键还是创意。很多动画其实不难实现,但是要让用户觉得有美感,挺有趣就有难度了。一个动画能让用户无聊的时候会点了玩玩,那这个动画就成功了。

作者:levi
comments powered by Disqus