在新iOS的音乐应用程序中,我们可以看到一个模糊的视图后面有一个专辑封面。
这样的事情是如何完成的呢?我看了文件,但什么都没发现。
在新iOS的音乐应用程序中,我们可以看到一个模糊的视图后面有一个专辑封面。
这样的事情是如何完成的呢?我看了文件,但什么都没发现。
当前回答
下面是Swift中使用CIGaussianBlur的快速实现:
func blur(image image: UIImage) -> UIImage {
let radius: CGFloat = 20;
let context = CIContext(options: nil);
let inputImage = CIImage(CGImage: image.CGImage!);
let filter = CIFilter(name: "CIGaussianBlur");
filter?.setValue(inputImage, forKey: kCIInputImageKey);
filter?.setValue("\(radius)", forKey:kCIInputRadiusKey);
let result = filter?.valueForKey(kCIOutputImageKey) as! CIImage;
let rect = CGRectMake(radius * 2, radius * 2, image.size.width - radius * 4, image.size.height - radius * 4)
let cgImage = context.createCGImage(result, fromRect: rect);
let returnImage = UIImage(CGImage: cgImage);
return returnImage;
}
其他回答
核心形象
由于截图中的图像是静态的,你可以使用Core image中的CIGaussianBlur(需要iOS 6)。以下是示例:https://github.com/evanwdavis/Fun-with-Masks/blob/master/Fun%20with%20Masks/EWDBlurExampleVC.m
注意,这比本页上的其他选项要慢。
#import <QuartzCore/QuartzCore.h>
- (UIImage*) blur:(UIImage*)theImage
{
// ***********If you need re-orienting (e.g. trying to blur a photo taken from the device camera front facing camera in portrait mode)
// theImage = [self reOrientIfNeeded:theImage];
// create our blurred image
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *inputImage = [CIImage imageWithCGImage:theImage.CGImage];
// setting up Gaussian Blur (we could use one of many filters offered by Core Image)
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[filter setValue:inputImage forKey:kCIInputImageKey];
[filter setValue:[NSNumber numberWithFloat:15.0f] forKey:@"inputRadius"];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
// CIGaussianBlur has a tendency to shrink the image a little,
// this ensures it matches up exactly to the bounds of our original image
CGImageRef cgImage = [context createCGImage:result fromRect:[inputImage extent]];
UIImage *returnImage = [UIImage imageWithCGImage:cgImage];//create a UIImage for this function to "return" so that ARC can manage the memory of the blur... ARC can't manage CGImageRefs so we need to release it before this function "returns" and ends.
CGImageRelease(cgImage);//release CGImageRef because ARC doesn't manage this on its own.
return returnImage;
// *************** if you need scaling
// return [[self class] scaleIfNeeded:cgImage];
}
+(UIImage*) scaleIfNeeded:(CGImageRef)cgimg {
bool isRetina = [[[UIDevice currentDevice] systemVersion] intValue] >= 4 && [[UIScreen mainScreen] scale] == 2.0;
if (isRetina) {
return [UIImage imageWithCGImage:cgimg scale:2.0 orientation:UIImageOrientationUp];
} else {
return [UIImage imageWithCGImage:cgimg];
}
}
- (UIImage*) reOrientIfNeeded:(UIImage*)theImage{
if (theImage.imageOrientation != UIImageOrientationUp) {
CGAffineTransform reOrient = CGAffineTransformIdentity;
switch (theImage.imageOrientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, theImage.size.height);
reOrient = CGAffineTransformRotate(reOrient, M_PI);
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, 0);
reOrient = CGAffineTransformRotate(reOrient, M_PI_2);
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
reOrient = CGAffineTransformTranslate(reOrient, 0, theImage.size.height);
reOrient = CGAffineTransformRotate(reOrient, -M_PI_2);
break;
case UIImageOrientationUp:
case UIImageOrientationUpMirrored:
break;
}
switch (theImage.imageOrientation) {
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, 0);
reOrient = CGAffineTransformScale(reOrient, -1, 1);
break;
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
reOrient = CGAffineTransformTranslate(reOrient, theImage.size.height, 0);
reOrient = CGAffineTransformScale(reOrient, -1, 1);
break;
case UIImageOrientationUp:
case UIImageOrientationDown:
case UIImageOrientationLeft:
case UIImageOrientationRight:
break;
}
CGContextRef myContext = CGBitmapContextCreate(NULL, theImage.size.width, theImage.size.height, CGImageGetBitsPerComponent(theImage.CGImage), 0, CGImageGetColorSpace(theImage.CGImage), CGImageGetBitmapInfo(theImage.CGImage));
CGContextConcatCTM(myContext, reOrient);
switch (theImage.imageOrientation) {
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
CGContextDrawImage(myContext, CGRectMake(0,0,theImage.size.height,theImage.size.width), theImage.CGImage);
break;
default:
CGContextDrawImage(myContext, CGRectMake(0,0,theImage.size.width,theImage.size.height), theImage.CGImage);
break;
}
CGImageRef CGImg = CGBitmapContextCreateImage(myContext);
theImage = [UIImage imageWithCGImage:CGImg];
CGImageRelease(CGImg);
CGContextRelease(myContext);
}
return theImage;
}
叠加模糊(方块+高斯)
这实现了盒子和高斯模糊的混合。比非加速高斯快7倍,但不像盒子模糊那么难看。请在这里(Java插件版本)或这里(JavaScript版本)查看演示。该算法用于KDE和Camera+等。它不使用加速框架,但速度很快。
加速框架
In the session “Implementing Engaging UI on iOS” from WWDC 2013 Apple explains how to create a blurred background (at 14:30), and mentions a method applyLightEffect implemented in the sample code using Accelerate.framework. GPUImage uses OpenGL shaders to create dynamic blurs. It has several types of blur: GPUImageBoxBlurFilter, GPUImageFastBlurFilter, GaussianSelectiveBlur, GPUImageGaussianBlurFilter. There is even a GPUImageiOSBlurFilter that “should fully replicate the blur effect provided by iOS 7's control panel” (tweet, article). The article is detailed and informative.
-(UIImage *)blurryGPUImage:(UIImage *)image withBlurLevel:(NSInteger)blur { GPUImageFastBlurFilter *blurFilter = [GPUImageFastBlurFilter new]; blurFilter.blurSize = blur; UIImage *result = [blurFilter imageByFilteringImage:image]; return result; }
From indieambitions.com: Perform a blur using vImage. The algorithm is also used in iOS-RealTimeBlur. From Nick Lockwood: https://github.com/nicklockwood/FXBlurView The example shows the blur over a scroll view. It blurs with dispatch_async, then syncs to call updates with UITrackingRunLoopMode so the blur is not lagged when UIKit gives more priority to the scroll of the UIScrollView. This is explained in Nick's book iOS Core Animation, which btw it's great. iOS-blur This takes the blurring layer of the UIToolbar and puts it elsewhere. Apple will reject your app if you use this method. See https://github.com/mochidev/MDBlurView/issues/4 From Evadne blog: LiveFrost: Fast, Synchronous UIView Snapshot Convolving. Great code and a great read. Some ideas from this post: Use a serial queue to throttle updates from CADisplayLink. Reuse bitmap contexts unless bounds change. Draw smaller images using -[CALayer renderInContext:] with a 0.5f scale factor.
其他东西
安迪·马图斯查克在推特上说:“你知道,在很多地方,我们看起来是实时的,但它是静态的,用的是聪明的技巧。”
在doubleencore.com网站上,他们说:“我们发现,在大多数情况下,10点模糊半径加上10点饱和度的增加最能模拟iOS 7的模糊效果。”
苹果sbfproceuralwallpaperview的私有头文件。
最后,这不是一个真正的模糊,但记住你可以设置rasterizationScale来获得一个像素化的图像:http://www.dimzzy.com/blog/2010/11/blur-effect-for-uiview/
我认为最简单的解决方案是覆盖UIToolbar,它在iOS 7中模糊了它后面的所有东西。这很狡猾,但实现起来非常简单,而且速度很快!
你可以对任何视图这么做,只是让它成为UIToolbar的子类而不是UIView。你甚至可以用UIViewController的view属性来做,例如…
1)创建一个新类,它是UIViewController的“子类”,并选中“With XIB for user interface”。
2)选择View,进入右边面板中的标识检查器(alt-command-3)。将“Class”改为UIToolbar。现在转到属性检查器(alt-command-4),将“背景”颜色改为“清色”。
3)在主视图中添加子视图,并将其连接到接口中的IBOutlet。叫它backgroundColorView。它看起来像这样,是实现(.m)文件中的一个私有类别。
@interface BlurExampleViewController ()
@property (weak, nonatomic) IBOutlet UIView *backgroundColorView;
@end
4)转到视图控制器实现(.m)文件并更改-viewDidLoad方法,如下所示:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.barStyle = UIBarStyleBlack; // this will give a black blur as in the original post
self.backgroundColorView.opaque = NO;
self.backgroundColorView.alpha = 0.5;
self.backgroundColorView.backgroundColor = [UIColor colorWithWhite:0.3 alpha:1];
}
这将给你一个深灰色的视图,它模糊了它后面的一切。没有有趣的业务,没有缓慢的核心图像模糊,使用操作系统/SDK提供的一切。
你可以将这个视图控制器的视图添加到另一个视图,如下所示:
[self addChildViewController:self.blurViewController];
[self.view addSubview:self.blurViewController.view];
[self.blurViewController didMoveToParentViewController:self];
// animate the self.blurViewController into view
如果有什么不清楚的地方请告诉我,我很乐意帮忙!
Edit
UIToolbar在7.0.3中被改变,当使用彩色模糊时可能会产生不希望看到的效果。
我们过去能够使用barTintColor设置颜色,但如果你以前这样做,你将需要将alpha组件设置为小于1。否则你的UIToolbar将是完全不透明的颜色-没有模糊。
这可以通过如下方式实现:(记住self是UIToolbar的子类)
UIColor *color = [UIColor blueColor]; // for example
self.barTintColor = [color colorWithAlphaComponent:0.5];
这将给模糊的视图一个蓝色的色调。
如果为tableView添加一个暗模糊视图,这将漂亮地使它:
tableView.backgroundColor = .clear
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = tableView.bounds
blurEffectView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
// Assigning blurEffectView to backgroundView instead of addSubview to tableView makes tableView cell not blocked by blurEffectView
tableView.backgroundView = blurEffectView
我不认为我被允许发布代码,但上面提到的WWDC示例代码是正确的。链接如下:https://developer.apple.com/downloads/index.action?name=WWDC%202013
你要找的文件是UIImage上的category,方法是applyLightEffect。
正如我在上面的评论中提到的,除了模糊,苹果模糊还有饱和度和其他东西。简单的模糊是不行的……如果你想模仿他们的风格。
这个答案是基于Mitja Semolic之前出色的回答。我已经将它转换为swift 3,添加了一个解释,在评论中发生了什么,使它成为一个UIViewController的扩展,这样任何VC都可以随意调用它,添加了一个未模糊的视图来显示选择性应用,并添加了一个完成块,以便调用视图控制器可以在完成模糊时做任何它想做的事情。
import UIKit
//This extension implements a blur to the entire screen, puts up a HUD and then waits and dismisses the view.
extension UIViewController {
func blurAndShowHUD(duration: Double, message: String, completion: @escaping () -> Void) { //with completion block
//1. Create the blur effect & the view it will occupy
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.light)
let blurEffectView = UIVisualEffectView()//(effect: blurEffect)
blurEffectView.frame = self.view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
//2. Add the effect view to the main view
self.view.addSubview(blurEffectView)
//3. Create the hud and add it to the main view
let hud = HudView.getHUD(view: self.view, withMessage: message)
self.view.addSubview(hud)
//4. Begin applying the blur effect to the effect view
UIView.animate(withDuration: 0.01, animations: {
blurEffectView.effect = blurEffect
})
//5. Halt the blur effects application to achieve the desired blur radius
self.view.pauseAnimationsInThisView(delay: 0.004)
//6. Remove the view (& the HUD) after the completion of the duration
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
blurEffectView.removeFromSuperview()
hud.removeFromSuperview()
self.view.resumeAnimationsInThisView()
completion()
}
}
}
extension UIView {
public func pauseAnimationsInThisView(delay: Double) {
let time = delay + CFAbsoluteTimeGetCurrent()
let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, time, 0, 0, 0, { timer in
let layer = self.layer
let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil)
layer.speed = 0.0
layer.timeOffset = pausedTime
})
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
}
public func resumeAnimationsInThisView() {
let pausedTime = layer.timeOffset
layer.speed = 1.0
layer.timeOffset = 0.0
layer.beginTime = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
}
}
我已经确认它适用于iOS 10.3.1和iOS 11