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
时间: 2024-10-05 05:05:43

iOS_自定义毛玻璃效果的相关文章

关于自定义毛玻璃的随笔(三方使用的翻译)

写项目登录页面的背景图的时候, 要用到毛玻璃, 想要的效果是这样的: 于是我用系统提供的毛玻璃的方法写了出来: UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; UIVisualEffectView *visualView = [[UIVisualEffectView alloc] initWithEffect:effect]; visualView.frame = [[UIScreen ma

Android Studio - 第四十七期 毛玻璃效果以及动态生成二维码以及增大点击热区

最近回看撸撸的代码,有一些自定义的view写法很不错,下面封装出来,希望能帮到大家: 1.毛玻璃效果:BitmapUtils package com.example.p030_popbgqcode.utils; import android.content.Context; import android.graphics.Bitmap; import android.renderscript.Allocation; import android.renderscript.Element; imp

移动端UI设计越来越流行的高斯模糊(Gaussian blur)和毛玻璃效果(磨砂效果),如何使用Android RenderScript简单实现?

高斯模糊(Gaussian blur)和毛玻璃效果(亦称磨砂效果),近两年在移动端的UI设计上越来越流行,特别是iOS手机上出现的较多,iOS系统也提供了相应的API帮助开发人员分分钟实现这两个效果.而Android系统则经历了一个漫长的探索过程,对图片的处理,从Java算法到NDK方式实现等,各种摸索层出不穷. 值得欣慰的是,Google终于在API 11中引入了 RenderScript ,一个强大的图片处理框架,帮助Android开发人员专注于图片处理算法而不是API的调度工作.使用Ren

Android高斯模糊技术,实现毛玻璃效果(转)

本博客转自郭霖公众号:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650235930&idx=1&sn=e328709c41ae208a9e41ef79d38cbeed&scene=24&srcid=09104fpQDG98JcRcUB9Ec7BN#wechat_redirect http://blog.csdn.net/grp0916/article/details/50494712 Android高

用swing实现了io7的毛玻璃效果

话不多说,上图 我new 了一些按钮,每个按钮的位置和背景颜色是随机的,其中有一些按钮的背景色每隔一秒变一次,拖动顶层panel,panel下的所有控件都将会模糊,而且是实时和动态的,比如下图,按钮为选择状态 panel背后的有些按钮在实时的变色,同样可以及时的模糊,模糊效果在很多应用上可以使用,模糊的背景能减弱视觉疲劳,还可以吸引用户的注意力. 源码地址:http://download.csdn.net/detail/lw421058391/7731725 用swing实现了io7的毛玻璃效果

CSS遮罩效果和毛玻璃效果

前面的话 本文将详细介绍CSS遮罩效果和毛玻璃效果 遮罩效果 普通遮罩 一般地,处理全屏遮罩的方法是使用额外标签 <style>.overlay{ position:fixed; top: 0;right: 0;left: 0;bottom: 0; background:rgba(0,0,0,0.8); } .lightbox{ position:absolute; top: 0;right: 0;left: 0;bottom: 0; margin:auto; z-index:1; width

UIVIewController自定义切换效果-b

之前介绍动画时提过UIView的转场动画,但是开发中我们碰到更多的viewController的切换,ios中常见的viewcontroller切换有四种:模态视图,导航栏控制器,UITabBarController以及addchildviewcontroller,自定义viewcontroller动画切换也是ios7中的新特性,这里整理下常见的操作,outline如下(本文参考http://onevcat.com/2013/10/vc-transition-in-ios7/,代码下载地址为ht

用css使图片产生毛玻璃效果

毛玻璃的图片效果,使得其显示更加唯美,用户体验更佳,所以在手机端电脑端应用甚广 比如ios系统: 所以现在我们就来看看毛玻璃效果的实现方法吧: 首先这是html的主要内容: <div class="container"> <div class="mat_class"></div> <p class="word">SHOW TIME</p> </div> 这里container

毛玻璃效果简单实现

项目中需要运用到毛玻璃的效果.经过搜索查阅,踩了一些坑,找到了一条暂时可行的办法. 其中,核心的控件是使用RenderScript这个类,这个类属于jni类,在较低版本的Android系统中,是不具备它的相关方法的.所以我们只能使用support.v8里面的类.然而,support.v8并没有默认地放在新建工程中,因此我们需要自己去添加. 第一步:将D:\AndroidSdk\build-tools\23.0.1\renderscript\lib\packaged 目录下的armeabi-v7a