標籤:ios 毛玻璃 上下文
最終:
關鍵代碼:
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
iOS_自訂毛半透明效果