版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.06.26 |
前言
在app中,类似头条的视频播放,在播放列表里面,会有背景是处理成模糊效果的,这中效果给人很新奇的感觉。这一篇,就仿照实现头条的模糊效果。感兴趣的可以看看我写的其他小技巧
1. 实用小技巧(一):UIScrollView中上下左右滚动方向的判断
2. 实用小技巧(二):屏幕横竖屏的判断和相关逻辑
3.实用小技巧(三):点击手势屏蔽子视图的响应
4.实用小技巧(四):动态的增删标签视图
5.实用小技巧(五):通过相册或者相机更改图标
6.实用小技巧(六):打印ios里所有字体
7. 实用小技巧(七):UITableViewCell自适应行高的计算
8. 实用小技巧(八):数字余额显示的分隔
实现目标
类似头条的视频,会有很多模糊的效果,我截了两张图,大约就是这个效果。
大家可以看见熊猫和吾六一两边的都是模糊的效果。下面我就实现一个这种效果。
实现过程
下面还是直接看代码,写一个UIImageView的分类。
#import <Foundation/Foundation.h>
@interface UIImageView (ZBUntil)
- (void)sd_setGaussFuzzyImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder;
@end
#import "UIImageView+ZBUntil.h"
@implementation UIImageView (ZBUntil)
- (void)sd_setGaussFuzzyImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder
{
self.contentMode = UIViewContentModeScaleToFill;
NSArray *subViewsArr = self.subviews;
[subViewsArr enumerateObjectsUsingBlock:^(UIView *obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (obj.tag == 100) {
[obj removeFromSuperview];
}
}];
UIImageView *gaosiView = [[UIImageView alloc] init];
gaosiView.tag = 100;
gaosiView.contentMode = UIViewContentModeScaleAspectFit;
[self addSubview:gaosiView];
[gaosiView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.right.top.bottom.mas_equalTo(self);
}];
gaosiView.image = [UIImage boxblurImage:placeholder withBlurNumber:0.5f];
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if (image) {
self.image = [UIImage boxblurImage:image withBlurNumber:0.5f];
gaosiView.image = image;
}
}];
}
@end
+ (UIImage *)boxblurImage:(UIImage *)image withBlurNumber:(CGFloat)blu;
+(UIImage *)boxblurImage:(UIImage *)image withBlurNumber:(CGFloat)blur
{
if (!image) {
return nil;
}
if (blur < 0.f || blur > 1.f) {
blur = 0.5f;
}
int boxSize = (int)(blur * 40);
boxSize = boxSize - (boxSize % 2) + 1;
CGImageRef img = image.CGImage;
vImage_Buffer inBuffer, outBuffer;
vImage_Error error;
void *pixelBuffer;
//从CGImage中获取数据
CGDataProviderRef inProvider = CGImageGetDataProvider(img);
CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
//设置从CGImage获取对象的属性
inBuffer.width = CGImageGetWidth(img);
inBuffer.height = CGImageGetHeight(img);
inBuffer.rowBytes = CGImageGetBytesPerRow(img);
inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
if(pixelBuffer == NULL)
NSLog(@"No pixelbuffer");
outBuffer.data = pixelBuffer;
outBuffer.width = CGImageGetWidth(img);
outBuffer.height = CGImageGetHeight(img);
outBuffer.rowBytes = CGImageGetBytesPerRow(img);
error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
if (error) {
NSLog(@"error from convolution %ld", error);
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate( outBuffer.data, outBuffer.width, outBuffer.height, 8, outBuffer.rowBytes, colorSpace, kCGImageAlphaNoneSkipLast);
CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
//clean up CGContextRelease(ctx);
CGColorSpaceRelease(colorSpace);
free(pixelBuffer);
CFRelease(inBitmapData);
CGColorSpaceRelease(colorSpace);
CGImageRelease(imageRef);
return returnImage;
}
这里有几句代码我一开始的时候并没有加。
NSArray *subViewsArr = self.subviews;
[subViewsArr enumerateObjectsUsingBlock:^(UIView *obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (obj.tag == 100) {
[obj removeFromSuperview];
}
}];
但是,如果不加,就会发现有些对象释放不掉,运行出来的视图查看层次也是很多叠在一起的。效果如下:
下面我们查看图层。
大家可以看到效果1中有间隙漏出来了,效果2中图像根本不对,上一个cell的图像漏出来了,说明上一个图像并没有释放。加上我刚才写的那几行代码就可以了,就可以释放和正常显示了。
实现效果
下面我们看一下最终的实现效果。
后记
这个效果挺有意思,就是一个高斯模糊,希望大家感兴趣的留言讨论,谢谢大家。