微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ios – UITableViewCell contentView背景的快速模糊

我已经制作了一个符合UITableViewDataSource和UITableViewDelegate协议的UIViewController,并且有一个UITableView作为它的子视图.

我已将表的backgroundView属性设置为UIImageView,以便将图像显示为表格的背景.

为了在单元格之间有自定义间距我使行高比我想要的大,并将单元格的contentView自定义为我想要的大小,使它看起来像有额外的空间(Following this SO answer).

我想为单元格添加一个模糊,以便背景模糊,我在Brad Larson’s GPUImage framework中做到了这一点.然而,这很好,因为我希望背景模糊在滚动时更新,滚动变得非常迟钝.

我的代码是:

//Gets called from the -scrollViewDidScroll:(UIScrollView *)scrollView method
- (void)updateViewBG
{
    UIImage *superviewImage = [self snapshotOfSuperview:self.tableView];

    UIImage* newBG = [self applyTint:self.tintColour image:[filter imageByFilteringImage:superviewImage]];

    self.layer.contents = (id)newBG.CGImage;
    self.layer.contentsScale = newBG.scale;
}

//Code to create an image from the area behind the 'blurred cell'
- (UIImage *)snapshotOfSuperview:(UIView *)superview
{
    CGFloat scale = 0.5;
    if (([UIScreen mainScreen].scale > 1 || self.contentMode == UIViewContentModeScaleAspectFill)) {
        CGFloat blockSize = 12.0f/5;
        scale = blockSize/MAX(blockSize * 2,floor(self.blurRadius));
    }

    UIGraphicsBeginImageContextWithOptions(self.bounds.size,YES,scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context,-self.frame.origin.x,-self.frame.origin.y);
    NSArray *hiddenViews = [self prepareSuperviewForSnapshot:superview];
    [superview.layer renderInContext:context];
    [self restoreSuperviewAfterSnapshot:hiddenViews];
    UIImage *snapshot = UIGraphicsGetimageFromCurrentimageContext();
    UIGraphicsEndImageContext();
    return snapshot;
}

-(UIImage*)applyTint:(UIColor*)colour image:(UIImage*)inImage{
    UIImage *newImage;
    if (colour) {
        UIGraphicsBeginImageContext(inImage.size);

        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGRect area = CGRectMake(0,inImage.size.width,inImage.size.height);

        CGContextScaleCTM(ctx,1,-1);
        CGContextTranslateCTM(ctx,-area.size.height);
        CGContextSaveGState(ctx);
        CGContextClipToMask(ctx,area,inImage.CGImage);
        [[colour colorWithAlphaComponent:0.8] set];
        CGContextFillRect(ctx,area);
        CGContextRestoreGState(ctx);
        CGContextSetBlendMode(ctx,kCGBlendModeLighten);
        CGContextDrawImage(ctx,inImage.CGImage);
        newImage = UIGraphicsGetimageFromCurrentimageContext();
        UIGraphicsEndImageContext();
    } else {
        newImage = inImage;
    }
    return newImage;
}

现在提问:
有没有更好的方法添加模糊?也许是为了不必渲染图层的每一个动作? iOS7的控制中心/通知中心似乎能够做到这一点,没有任何滞后.

也许使用GPUImageUIElement类?如果是这样,我该如何使用它?
我看到的另一种方法是最初在背景图像上创建模糊然后裁剪我需要使用的区域,但是我无法使其工作,因为图像的大小可能与也可能不同屏幕因此缩放是一个问题(使用CGImageCreateWithImageInRect()和矩形是单元格在表上的位置).

我还发现我必须将模糊添加到tableview本身,框架是单元格的框架,而单元格具有清晰的颜色.

提前致谢

编辑
根据要求,这是我之前尝试的图像裁剪的代码

- (void)updateViewBG
{
    //self.bgImg is the pre-blurred image,-getContentViewFromCellFrame: is a convenience method to get just the content area from the whole cell (since the contentarea is smaller than the cell)
    UIImage* bg = [self cropImage:self.bgImg 
                           toRect:[LATableBlur getContentViewFromCellFrame:[self.tableView rectForRowAtIndexPath:self.cellIndexPath]]];
    bg = [self applyTint:self.tintColour image:bg];
    self.layer.contents = (id)bg.CGImage;
    self.layer.contentsScale = bg.scale;
}

- (UIImage*)cropImage:(UIImage*)image toRect:(CGRect)frame
{
    CGSize imgSize = [image size];
    double heightRatio = imgSize.height/self.tableView.frame.size.height;
    double widthRatio = imgSize.width/self.tableView.frame.size.width;

    UIImage* cropped = [UIImage imageWithCGImage:CGImageCreateWithImageInRect(image.CGImage,CGRectMake(frame.origin.x*widthRatio,frame.origin.y*heightRatio,frame.size.width*widthRatio,frame.size.height*heightRatio))];

    return cropped;
}

解决方法

我设法用一个解决方案来解决它,起初我认为它不会起作用.

生成几个模糊的图像肯定不是解决方案,因为它花费了很多.
我只使用了一个模糊的图像并将其缓存.

所以我将UITableViewCell子类化:

@interface BlurredCell : UITableViewCell
@end

我实现了两个类方法来访问缓存的图像(模糊和正常的)

+(UIImage *)normalImage
{
    static dispatch_once_t oncetoken;
    static UIImage *_normalImage;
    dispatch_once(&oncetoken,^{
        _normalImage = [UIImage imageNamed:@"bg.png"];
    });
    return _normalImage;
}

我在UIImage上使用了REFrostedViewController的类别来生成模糊图像

+(UIImage *)blurredImage
{
    static dispatch_once_t oncetoken;
    static UIImage *_blurredImage;
    dispatch_once(&oncetoken,^{
    _blurredImage = [[UIImage imageNamed:@"bg.png"] re_applyBlurWithRadius:BlurredCellBlurRadius
                                                                 tintColor:[UIColorcolorWithWhite:1.0f
                                                                                            alpha:0.4f]
                                                     saturationDeltaFactor:1.8f
                                                                 maskImage:nil];
    });
    return _blurredImage;
}

为了在单元格内部产生模糊帧的效果,但仍然看到两侧的非模糊图像,我习惯滚动视图.

一个是带有普通图像的图像视图,另一个是带有模糊图像的图像视图.我将内容大小设置为图像的大小,contentOffset将通过接口设置.

因此,表视图最终以每个单元格保存整个背景图像,但在特定偏移处裁剪它并仍然显示整个图像

@implementation BlurredCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(Nsstring *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
        [self.contentView addSubview:self.normalScrollView];
        [self.contentView addSubview:self.blurredScrollView];
    }
    return self;
}

-(UIScrollView *)normalScrollView
{
    if (!_normalScrollView) {
        _normalScrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
        _normalScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _normalScrollView.scrollEnabled = NO;
        UIImageView *imageView =[[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
        imageView.contentMode = UIViewContentModeScaletoFill;
        imageView.image = [BlurredCell normalImage];
        _normalScrollView.contentSize = imageView.frame.size;
        [_normalScrollView addSubview:imageView];
    }
    return _normalScrollView;
}

-(UIScrollView *)blurredScrollView
{
    if (!_blurredScrollView) {
        _blurredScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(BlurredCellPadding,BlurredCellPadding,self.bounds.size.width - 2.0f * BlurredCellPadding,self.bounds.size.height - 2.0f * BlurredCellPadding)];
        _blurredScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _blurredScrollView.scrollEnabled = NO;
        _blurredScrollView.contentOffset = CGPointMake(BlurredCellPadding,BlurredCellPadding);
        UIImageView *imageView =[[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
        imageView.contentMode = UIViewContentModeScaletoFill;
        imageView.image = [BlurredCell blurredImage];
        _blurredScrollView.contentSize = imageView.frame.size;
        [_blurredScrollView addSubview:imageView];
    }
    return _blurredScrollView;
}

-(void)setBlurredContentOffset:(CGFloat)offset
{
    self.normalScrollView.contentOffset = CGPointMake(self.normalScrollView.contentOffset.x,offset);
    self.blurredScrollView.contentOffset = CGPointMake(self.blurredScrollView.contentOffset.x,offset + BlurredCellPadding);
}

@end

setBlurredContentOffset:每次表视图的内容偏移量发生变化时都应该调用.

所以在表视图中委托的实现(视图控制器)我们在这两种方法中做到了:

// For the first rows
-(void)tableView:(UITableView *)tableView willdisplayCell:(BlurredCell *)cell 
                                        forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [cell setBlurredContentOffset:cell.frame.origin.y];
}

// Each time the table view is scrolled
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    for (BlurredCell *cell in [self.tableView visibleCells]) {
        [cell setBlurredContentOffset:cell.frame.origin.y - scrollView.contentOffset.y];
    }
}

这是complete working demo

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐