最终效果图:
关键代码:
UIImage分类代码
// // UIImage+BlurGlass.h // 帅哥_团购 // // Created by beyond on 14-8-30. // Copyright (c) 2014年 com.beyond. All rights reserved. // 毛玻璃效果 UIImage分类 #import <UIKit/UIKit.h> @interface UIImage (BlurGlass) /* 1.白色,参数: 透明度 0~1, 0为白, 1为深灰色 半径:默认30,推荐值 3 半径值越大越模糊 ,值越小越清楚 色彩饱和度(浓度)因子: 0是黑白灰, 9是浓彩色, 1是原色 默认1.8 “彩度”,英文是称Saturation,即饱和度。将无彩色的黑白灰定为0,最鲜艳定为9s,这样大致分成十阶段,让数值和人的感官直觉一致。 */ - (UIImage *)imgWithLightAlpha:(CGFloat)alpha radius:(CGFloat)radius colorSaturationFactor:(CGFloat)colorSaturationFactor; // 2.封装好,供外界调用的 - (UIImage *)imgWithBlur; @end
// // UIImage+BlurGlass.m // 帅哥_团购 // // Created by beyond on 14-8-30. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import "UIImage+BlurGlass.h" #import <Accelerate/Accelerate.h> @implementation UIImage (BlurGlass) /* 1.白色,参数: 透明度 0~1, 0为白, 1为深灰色 半径:默认30,推荐值 3 半径值越大越模糊 ,值越小越清楚 色彩饱和度(浓度)因子: 0是黑白灰, 9是浓彩色, 1是原色 默认1.8 “彩度”,英文是称Saturation,即饱和度。将无彩色的黑白灰定为0,最鲜艳定为9s,这样大致分成十阶段,让数值和人的感官直觉一致。 */ - (UIImage *)imgWithLightAlpha:(CGFloat)alpha radius:(CGFloat)radius colorSaturationFactor:(CGFloat)colorSaturationFactor { UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:alpha]; return [self imgBluredWithRadius:radius tintColor:tintColor saturationDeltaFactor:colorSaturationFactor maskImage:nil]; } // 2.封装好,供外界调用的 - (UIImage *)imgWithBlur { // 调用方法1 return [self imgWithLightAlpha:0.1 radius:3 colorSaturationFactor:1]; } // 内部方法,核心代码,封装了毛玻璃效果 参数:半径,颜色,色彩饱和度 - (UIImage *)imgBluredWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage { CGRect imageRect = { CGPointZero, self.size }; UIImage *effectImage = self; BOOL hasBlur = blurRadius > __FLT_EPSILON__; BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; if (hasBlur || hasSaturationChange) { UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); CGContextRef effectInContext = UIGraphicsGetCurrentContext(); CGContextScaleCTM(effectInContext, 1.0, -1.0); CGContextTranslateCTM(effectInContext, 0, -self.size.height); CGContextDrawImage(effectInContext, imageRect, self.CGImage); vImage_Buffer effectInBuffer; effectInBuffer.data = CGBitmapContextGetData(effectInContext); effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); vImage_Buffer effectOutBuffer; effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); if (hasBlur) { CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); if (radius % 2 != 1) { radius += 1; // force radius to be odd so that the three box-blur methodology works. } vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); } BOOL effectImageBuffersAreSwapped = NO; if (hasSaturationChange) { CGFloat s = saturationDeltaFactor; CGFloat floatingPointSaturationMatrix[] = { 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, 0, 0, 0, 1, }; const int32_t divisor = 256; NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); int16_t saturationMatrix[matrixSize]; for (NSUInteger i = 0; i < matrixSize; ++i) { saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); } if (hasBlur) { vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); effectImageBuffersAreSwapped = YES; } else { vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); } } if (!effectImageBuffersAreSwapped) effectImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if (effectImageBuffersAreSwapped) effectImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); } // 开启上下文 用于输出图像 UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); CGContextRef outputContext = UIGraphicsGetCurrentContext(); CGContextScaleCTM(outputContext, 1.0, -1.0); CGContextTranslateCTM(outputContext, 0, -self.size.height); // 开始画底图 CGContextDrawImage(outputContext, imageRect, self.CGImage); // 开始画模糊效果 if (hasBlur) { CGContextSaveGState(outputContext); if (maskImage) { CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); } CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); CGContextRestoreGState(outputContext); } // 添加颜色渲染 if (tintColor) { CGContextSaveGState(outputContext); CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); CGContextFillRect(outputContext, imageRect); CGContextRestoreGState(outputContext); } // 输出成品,并关闭上下文 UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return outputImage; } @end
控制器代码
// // MineController.m // 帅哥_团购 // // Created by beyond on 14-8-14. // Copyright (c) 2014年 com.beyond. All rights reserved. // dock上面的【我的】按钮对应的控制器 #import "MineController.h" #import "ImgDownloadTool.h" #import <Accelerate/Accelerate.h> #import "UIImage+BoxBlur.h" #import "GirlCell.h" // 每一个格子的宽和高 #define kItemW 240 #define kItemH 320 @interface MineController ()<UICollectionViewDataSource,UICollectionViewDelegate> { NSMutableArray *_imgArr; UIWebView *_webView; // 添加一个coverImgView,用于点击了cell时,进行屏幕截图并加上毛玻璃效果,置于最上方作为蒙板 UIImageView *_coverBlurImgView; // 点击cell,弹出一个大图(必须在控制器显示之前 再确定frame,真实的frame) UIImageView *_showingImgView; } @end @implementation MineController #pragma mark - 生命周期方法 - (void)viewDidLoad { [super viewDidLoad]; self.title = @"我的青春谁做主"; // 0.加载plist文件保存的url数组 // sg_bundle模板代码,1,获得.app主要的包;2,返回主要的包中某个文件的fullPath全路径 NSBundle *mainBundle = [NSBundle mainBundle]; NSString *fullPath = [mainBundle pathForResource:@"sinaImgArr.plist" ofType:nil]; _imgArr = [NSArray arrayWithContentsOfFile:fullPath]; // 1.创建自己的collectionView [self addCollectionView]; // 2.注册cell格子要用到的xib文件 [self.collectionView registerNib:[UINib nibWithNibName:@"GirlCell" bundle:nil] forCellWithReuseIdentifier:@"GirlCell"]; // 3.设置collectionView永远支持垂直滚动,为下拉刷新准备(弹簧) self.collectionView.alwaysBounceVertical = YES; // 4.设置collectionView的背景色 self.collectionView.backgroundColor = kGlobalBg; // 5.添加一个coverImgView,用于点击了cell时,进行屏幕截图并加上毛玻璃效果,置于最上方作为蒙板 _coverBlurImgView = [[UIImageView alloc]init]; [self.view addSubview:_coverBlurImgView]; // 6.点击cell,弹出一个大图(必须在控制器显示之前 再确定frame,真实的frame) _showingImgView = [[UIImageView alloc]init]; _showingImgView.backgroundColor = [UIColor clearColor]; [self.view addSubview:_showingImgView]; _showingImgView.contentMode = UIViewContentModeScaleAspectFit; _showingImgView.userInteractionEnabled = YES; [_showingImgView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showingImgTap)]]; } // 1.创建自己的collectionView - (void)addCollectionView { // 创建一个流布局,必须指定 UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; // 设置流布局里面的每一个格子宽和高,即每一个网格的尺寸 layout.itemSize = CGSizeMake(kItemW, kItemH); // 每一行之间的间距 layout.minimumLineSpacing = 20; // 指定的流布局创建一个collectionView,并且用成员变量记住 self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; // 高度和宽度自动伸缩 self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; self.collectionView.delegate = self; self.collectionView.dataSource = self; [self.view addSubview:self.collectionView]; } #pragma mark 在viewWillAppear和viewDidAppear中可以取得view最准确的宽高(width和height) // 重要~~~因为在控制器创建时,宽默认是768,高默认是1024,不管横竖屏 // 只有在viewWillAppear和viewDidAppear方法中,可以取得view最准确的(即实际的)宽和高(width和height) - (void)viewWillAppear:(BOOL)animated { // 默认计算layout [self didRotateFromInterfaceOrientation:0]; } #pragma mark - 父类方法 // 拦截,屏幕即将旋转的时候调用(控制器监控屏幕旋转) - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { //log(@"屏幕即将旋转"); } #pragma mark 屏幕旋转完毕的时候调用 // 拦截,屏幕旋转完毕的时候调用 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { // 1.取出创建CollectionViewController时传入的的UICollectionViewFlowLayout UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout; // 2.计算间距 CGFloat v = 0; CGFloat h = 0; CGFloat height = self.view.frame.size.height -44; CGFloat width = self.view.frame.size.width; if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation) ) { // 横屏的间距 v = (height - 2 * kItemH) / 3; h = (width - 3 * kItemW) / 4; } else { // 竖屏的间距 v = (height - 3 * kItemH) / 4; h = (width - 2 * kItemW) / 3; } // 3.动画调整格子之间的距离 [UIView animateWithDuration:4.0 animations:^{ // 上 左 下 右 四个方向的margin layout.sectionInset = UIEdgeInsetsMake(h, h, v, h); // 每一行之间的间距 layout.minimumLineSpacing = h; }]; // 4.旋转完成之后,才可以得到真实的frame,暂时隐藏起来,当点击cell的时侯才展示 -5 _coverBlurImgView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); _coverBlurImgView.hidden = YES; _showingImgView.hidden = YES; CGRect temp = _showingImgView.frame; CGFloat x =self.view.frame.size.width * 0.5; CGFloat y =self.view.frame.size.height * 0.5; temp = CGRectMake(x,y, 0, 0); _showingImgView.frame = temp; } #pragma mark - collectionView代理方法 // 共有多少个Item(就是格子Cube),询问子类 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return _imgArr.count; } #pragma mark 刷新数据的时候会调用(reloadData) #pragma mark 每当有一个cell重新进入屏幕视野范围内就会调用 // 生成每一个独一无二的格子,询问子类 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID = @"GirlCell"; GirlCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath]; cell.imgSrc = _imgArr[indexPath.row]; return cell; } // 点击了一个格子时,1,截屏,2,动画毛玻璃图片,3,showing从小放到大 - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { // 1,截屏 [self screenShot]; // 2,显示 _coverBlurImgView.alpha = 1; _coverBlurImgView.hidden = NO; // 3.调用UIImage的分类方法,进行毛玻璃处理 _coverBlurImgView.image = [_coverBlurImgView.image imgWithBlur]; // 4.展示_showingImgView _showingImgView.hidden = NO; // 点击cell,弹出一个大图 CGRect temp = _showingImgView.frame; CGFloat x =self.view.frame.size.width * 0.5; CGFloat y =self.view.frame.size.height * 0.5; temp = CGRectMake(x,y, 0, 0); _showingImgView.frame = temp; _showingImgView.alpha = 0; [UIView animateWithDuration:0.5 animations:^{ [ImgDownloadTool imgDownloadWithUrl:_imgArr[indexPath.row] tmpImgName:kImgPlaceHolder imageView:_showingImgView]; _showingImgView.alpha = 1; _showingImgView.frame = self.view.bounds; }]; } // 使用上下文截图,并使用指定的区域裁剪,模板代码 - (void)screenShot { // 将要被截图的view // 背景图片 总的大小 CGSize size = self.view.frame.size; UIGraphicsBeginImageContext(size); // 开启上下文,使用参数之后,截出来的是原图(YES 0.0 质量高) UIGraphicsBeginImageContextWithOptions(size, YES, 0.0); // 裁剪的关键代码,要裁剪的矩形范围 CGRect rect = CGRectMake(0, 0, size.width, size.height ); //注:iOS7以后renderInContext:由drawViewHierarchyInRect:afterScreenUpdates:替代 [self.view drawViewHierarchyInRect:rect afterScreenUpdates:NO]; // 从上下文中,取出UIImage UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext(); // 添加截取好的图片到图片View里面 _coverBlurImgView.image = snapshot; // 千万记得,结束上下文(移除栈顶上下文) UIGraphicsEndImageContext(); } // 正在显示的大图被点了 - (void)showingImgTap { [UIView animateWithDuration:0.5 animations:^{ CGRect temp = _showingImgView.frame; CGFloat x =self.view.frame.size.width * 0.5; CGFloat y =self.view.frame.size.height * 0.5; temp = CGRectMake(x,y, 0, 0); _showingImgView.frame = temp; _showingImgView.alpha = 0; } completion:^(BOOL finished) { // 隐藏起来 _showingImgView.hidden = YES; _coverBlurImgView.hidden = YES; }]; } #pragma mark - 生命周期方法 - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } @end