天天看點

iOS通知欄磨砂透明背景的代碼實作(高斯模糊)

方法一.使用UIToolBar可以支援iOS7之後的高斯模糊效果

利用UIToolbar來實作是最簡單的毛玻璃效果。需要什麼控件自行添加到toolbar上就OK。

初始化UIToolbar,設定toolbar樣式為UIBarStyleBlackTranslucent或者UIBarStyleBlackOpaque 即可。修改bartintcolor的RGB值 可修改毛玻璃色調效果。

通過本人親身嘗試,其實UIToolBar,UINavigationBar,UITabbar在IOS7上都會有高斯效果,當然,有些機型不支援(後面會總結),然後他們的表現都是一模一樣的,細微的差别就是各個控件上的邊框多了一些圓角,橫線,但是實作高斯效果的類都是用同一個。具體是什麼類,可以去研究一下,這裡不深入介紹那個類,隻講怎麼使用 高斯效果有系統提供的有兩種效果,白色底和黑色底。具體通過設定UIBarStyle屬性去設定,有UIBarStyleDefault和UIBarStyleBlack,這兩種效果對比起來,Black的效果最佳,是以現在在系統本身,都是用Black樣式。 但是有人想,如果隻有這兩種樣式,能不能通過修改一些屬性去改變樣式呢。下面嘗試了幾種方法 1.alpha值 通過修改alpha值,發現,如果alpha值不為1,那麼就沒有高斯效果,假如你對UIToolbar進行alpha值漸變,你會發現隻有等到為1的時候才會有效果,是以alpha值不能修改,會導緻高斯模糊失效 2.mask 由于UIToolbar隻有是矩形的樣式,我們可以通過mask屬性對圖像進行處理,通過根據我們自定的圖形,mask對應的圖形,但是,如果你使用了mask,那麼很不好意思,高斯模糊沒有了。 3.tintColor 設定了沒效果 4.barTintColor 這個是設定bar 背景顔色,設定之後,發現有效果,但是效果不明顯,有興趣可以設定一下 至于其他屬性,有興趣可以去設定一下,我是沒找到其他屬性了

根據好幾天的接觸,發現了IOS7的高斯模糊的一個特點,由于系統是支援實時更新,這部分運算明顯是有效率問題的,但是我們發現,系統的好像感覺不到效率問題。通過觀察,發現,如果背景圖檔顔色比較單一,簡單,高斯模糊效果很一般,有時候就隻是簡單的alpha透明過去,如果背景顔色塊比較明顯,那麼高斯效果就很清晰,可見蘋果對這個的處理還是做了優化,而不是每時每刻都在重新整理界面,不然效率肯定提不上來。 機型限制,目前隻支援IOS7系統,4s和以上的機型,touch5, ipad上螢幕較大,支援ipad4以上

示例代碼:

@property (weak, nonatomic) IBOutlet UIToolbar *bottomTabsBarBlurBgView;
@property (weak, nonatomic) IBOutlet SingleSelectTabsView *bottomTabsBar;


- (void)awakeFromNib
{
    [super awakeFromNib];

    self.bottomTabsBarBlurBgView.barStyle = UIBarStyleBlack;
    self.bottomTabsBarBlurBgView.hidden = IS_AT_LEAST_IOS7 ? NO : YES;
    self.bottomTabsBar.alpha = IS_AT_LEAST_IOS7 ? 1 : 0.95;
    self.bottomTabsBar.backgroundColor = IS_AT_LEAST_IOS7 ? UIColorFromRGB(255, 255, 255, 0) : UIColorFromRGB(25, 25, 25, 1);

}
           
iOS通知欄磨砂透明背景的代碼實作(高斯模糊)
iOS通知欄磨砂透明背景的代碼實作(高斯模糊)
iOS通知欄磨砂透明背景的代碼實作(高斯模糊)

方法二.通過圖檔處理+實時重新整理的方法實作(但是有性能問題)

(1).工程中添加Accelerate.framework。

(2).添加Category檔案UIImage+ImageEffects.h/UIImage+ImageEffects.m.

#import <UIKit/UIKit.h>

@interface UIImage (ImageEffects)

- (UIImage *)applyLightEffect;
- (UIImage *)applyExtraLightEffect;
- (UIImage *)applyDarkEffect;
- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor;

- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage;

@end
           
#import "UIImage+ImageEffects.h"

#import <Accelerate/Accelerate.h>
#import <float.h>


@implementation UIImage (ImageEffects)


- (UIImage *)applyLightEffect
{
    UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
    return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
}


- (UIImage *)applyExtraLightEffect
{
    UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82];
    return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
}


- (UIImage *)applyDarkEffect
{
    UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73];
    return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
}


- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor
{
    const CGFloat EffectColorAlpha = 0.6;
    UIColor *effectColor = tintColor;
    int componentCount = CGColorGetNumberOfComponents(tintColor.CGColor);
    if (componentCount == 2) {
        CGFloat b;
        if ([tintColor getWhite:&b alpha:NULL]) {
            effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
        }
    }
    else {
        CGFloat r, g, b;
        if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
            effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
        }
    }
    return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil];
}


- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage
{
    // Check pre-conditions.
    if (self.size.width < 1 || self.size.height < 1) {
        NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self);
        return nil;
    }
    if (!self.CGImage) {
        NSLog (@"*** error: image must be backed by a CGImage: %@", self);
        return nil;
    }
    if (maskImage && !maskImage.CGImage) {
        NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage);
        return nil;
    }
    
    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) {
            // A description of how to compute the box kernel width from the Gaussian
            // radius (aka standard deviation) appears in the SVG spec:
            // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
            //
            // For larger values of 's' (s >= 2.0), an approximation can be used: Three
            // successive box-blurs build a piece-wise quadratic convolution kernel, which
            // approximates the Gaussian kernel to within roughly 3%.
            //
            // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5)
            //
            // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel.
            //
            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();
    }
    
    // Set up output context.
    UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
    CGContextRef outputContext = UIGraphicsGetCurrentContext();
    CGContextScaleCTM(outputContext, 1.0, -1.0);
    CGContextTranslateCTM(outputContext, 0, -self.size.height);
    
    // Draw base image.
    CGContextDrawImage(outputContext, imageRect, self.CGImage);
    
    // Draw effect image.
    if (hasBlur) {
        CGContextSaveGState(outputContext);
        if (maskImage) {
            CGContextClipToMask(outputContext, imageRect, maskImage.CGImage);
        }
        CGContextDrawImage(outputContext, imageRect, effectImage.CGImage);
        CGContextRestoreGState(outputContext);
    }
    
    // Add in color tint.
    if (tintColor) {
        CGContextSaveGState(outputContext);
        CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
        CGContextFillRect(outputContext, imageRect);
        CGContextRestoreGState(outputContext);
    }
    
    // Output image is ready.
    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return outputImage;
}


@end
           

(3).使用Sample代碼(圖檔可以通過截屏背景得到,進而有磨砂透明的蓋層效果)。————>蘋果官方Demo<————

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    const CGFloat fontSize = 25.f;
    const NSString *text = @"Over layer string.";
    CGSize size = [text sizeWithAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"Avenir Next" size:fontSize]}];
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(30, 200, size.width, size.height)];
    label.font = [UIFont fontWithName:@"Avenir Next" size:fontSize];
    label.textAlignment = NSTextAlignmentNatural;
    label.backgroundColor = [UIColor clearColor];
    label.text = (NSString *)text;
    
    UIImage *image = [UIImage imageNamed:@"wat.png"];
    UIImage *blurredImage = [image applyBlurWithRadius:10 tintColor:[UIColor colorWithWhite:0 alpha:0.25] saturationDeltaFactor:1.f maskImage:nil];
    
    UIImageView *imageView = [[UIImageView alloc] initWithImage:blurredImage];
    imageView.frame = CGRectMake(0, 0, 500, 375);
    
    CGFloat imgScale = image.scale;
    CGRect labelFrame = label.frame;
    CGRect realRect = CGRectMake(labelFrame.origin.x * imgScale, labelFrame.origin.y * imgScale, labelFrame.size.width * imgScale, labelFrame.size.height * imgScale);
    CGImageRef labelPatternImage = CGImageCreateWithImageInRect(image.CGImage, realRect);
    label.textColor = [UIColor colorWithPatternImage:[UIImage imageWithCGImage:labelPatternImage scale:image.scale orientation:UIImageOrientationUp]];
    CGImageRelease(labelPatternImage);
    
    [self.view addSubview:imageView];
    [self.view addSubview:label];
}
           

繼續閱讀