zoukankan      html  css  js  c++  java
  • 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上面的【我的】button相应的控制器
    
    #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
    









  • 相关阅读:
    构建之法阅读笔记2
    2020.2.10
    2020.2.9
    2020.2.8
    2020.2.7
    2020.2.6
    2020.2.5
    学习进度——第十三周
    PHPStorm+XAMPP开发php项目
    第一阶段成果建议
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7070545.html
Copyright © 2011-2022 走看看