使用“带模糊的视觉效果视图”减少模糊?
Less Blur with `Visual Effect View with Blur`?
标题几乎问了一切...
我正在玩 iOS8 Visual Effect View with Blur
。它位于显示用户可选择的背景照片的 UIImageView
上方。放置在contentView中的视图本身就是我自己的自定义视图,显示了一种graph/calendar。大部分所说的日历图是透明的。它应用于它后面的照片的模糊真的很重。我想让更多的细节泄露出去。但是Apple似乎只给出了三个罐装值:
typedef enum {
UIBlurEffectStyleExtraLight,
UIBlurEffectStyleLight,
UIBlurEffectStyleDark
} UIBlurEffectStyle;
我已经用 UIVisualEffectView
的不同 alpha 和背景颜色进行了修改(尽管文档警告不要这样做),但这只会让事情变得更糟。
模糊严重的原因是模糊效果样式影响图像的亮度级别,而不是应用的模糊量。
不幸的是,尽管 Apple 显然有能力以编程方式控制应用的模糊量——尝试在启动板上缓慢向下拖动以观看 Spotlight 模糊过渡——我没有看到任何 publicAPI 将模糊量传递给 UIBlurEffect
。
此 post 声称调整背景颜色 alpha 会增加模糊量。值得一试,但我看不到记录在哪里:
这对我有用。
在添加到我的视图之前,我将 UIVisualEffectView
放在 UIView
中。
我让这个功能更容易使用。您可以使用此功能模糊视图中的任何区域。
func addBlurArea(area: CGRect, style: UIBlurEffectStyle) {
let effect = UIBlurEffect(style: style)
let blurView = UIVisualEffectView(effect: effect)
let container = UIView(frame: area)
blurView.frame = CGRect(x: 0, y: 0, width: area.width, height: area.height)
container.addSubview(blurView)
container.alpha = 0.8
self.view.insertSubview(container, atIndex: 1)
}
例如,您可以通过调用以下命令使所有视图变得模糊:
addBlurArea(self.view.frame, style: UIBlurEffectStyle.Dark)
您可以将 Dark
更改为您想要的模糊样式,并将 0.8
更改为您想要的 alpha 值
遗憾的是Apple没有提供任何模糊效果的选项。但这个解决方法对我有用 - 动画模糊效果并在完成前暂停它。
func blurEffectView(enable enable: Bool) {
let enabled = self.blurView.effect != nil
guard enable != enabled else { return }
switch enable {
case true:
let blurEffect = UIBlurEffect(style: .ExtraLight)
UIView.animateWithDuration(1.5) {
self.blurView.effect = blurEffect
}
self.blurView.pauseAnimation(delay: 0.3)
case false:
self.blurView.resumeAnimation()
UIView.animateWithDuration(0.1) {
self.blurView.effect = nil
}
}
}
以及用于暂停(延迟)和恢复视图动画的 UIView 扩展
extension UIView {
public func pauseAnimation(delay 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(), fromLayer: nil)
layer.speed = 0.0
layer.timeOffset = pausedTime
})
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes)
}
public func resumeAnimation() {
let pausedTime = layer.timeOffset
layer.speed = 1.0
layer.timeOffset = 0.0
layer.beginTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime
}
}
您可以在图像上添加 UIBlurEffect。这样就可以了。
这是一个带有模糊效果的 UIImageView 示例。记得给 UIImageView 添加一个 Image。
调整模糊量 blurEffectView.alpha = 0.8(从 0 到 1)
import UIKit
class BlurEffectImageView: UIImageView {
override func awakeFromNib() {
super.awakeFromNib()
addBlurEffect()
}
private func addBlurEffect() {
let blurEffect = UIBlurEffect(style: .light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.alpha = 0.8
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
blurEffectView.translatesAutoresizingMaskIntoConstraints = false
addSubview(blurEffectView)
NSLayoutConstraint(item: blurEffectView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: blurEffectView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: blurEffectView, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: blurEffectView, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1.0, constant: 0).isActive = true
}
}
将 BlurEffectView 添加到视图的 alpha < 1 的视图
func addBlurEffectView() -> Void {
if !UIAccessibilityIsReduceTransparencyEnabled() {
let viewContainer = UIView()
viewContainer.frame = self.view.bounds
viewContainer.alpha = 0.5
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.layer.zPosition = -0.5;
blurEffectView.frame = self.view.bounds;
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
viewContainer.addSubview(blurEffectView)
self.view.addSubview(viewContainer)
self.view.sendSubview(toBack: viewContainer)
}
}
此答案基于。我已将其转换为 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
一种类似于此处的解决方案,但更简单,是使用 UIViewPropertyAnimator (iOS 10+) 并将其 fractionComplete
属性 设置为介于 0 和 1 之间的某个值。
// add blur view to image view
let imgBlur = UIVisualEffectView()
imgView.addSubview(imgBlur)
imgBlur.frame = imgView.bounds
// create animator to control blur strength
let imgBlurAnimator = UIViewPropertyAnimator()
imgBlurAnimator.addAnimations {
imgBlur.effect = UIBlurEffect(style: .dark)
}
// 50% blur
imgBlurAnimator.fractionComplete = 0.5
请注意,如果您打算根据平移手势、滚动视图、滑块等改变 fractionComplete
,您需要设置 pausesOnCompletion = true
(iOS 11+) .
我像这样使用 UIVisualEffectView 来获得可调整的模糊圆圈。模糊级别由控制 alpha 的滑块控制。我还将在下面包含滑块处理程序。模糊圆圈大小可通过捏张动作进行调整。我也会包括在内。您可以在模糊圆圈周围拖动。我将把它留作 reader 的练习。如果你想要一个模糊的矩形,只是不要圆角。要查看此模糊圆圈设计的实际效果,请加载 MemeSoEasy 应用程序(免费),添加一张照片(您可以在其上放置一个模糊圆圈),然后添加一个模糊圆圈。
UIVisualEffectView *blurVisualEffectView;
UIVisualEffect *blurEffect;
blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
blurVisualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
blurVisualEffectView.frame = lastChosenBlurCircleRect;
blurVisualEffectView.center = CGPointMake(halfScreenX, halfScreenY);
[self.view addSubview:blurVisualEffectView];
CGFloat blurCornerRadius = blurVisualEffectView.bounds.size.width/2;
[[blurVisualEffectView layer]setCornerRadius:blurCornerRadius];
[[blurVisualEffectView layer]setMasksToBounds:YES];
[[blurVisualEffectView layer] setBorderWidth:4.0f];
[[blurVisualEffectView layer] setBorderColor:[UIColor blueColor].CGColor];
blurVisualEffectView.userInteractionEnabled = NO;
blurVisualEffectView.alpha = 0.97;
[blurArray addObject:blurVisualEffectView];
滑块处理程序:
请注意,我将模糊对象存储在一个数组中,因此我可以让用户根据需要创建任意数量的对象。滑块处理程序处理数组中的最后一个对象。滑块最小值和最大值为 0.0 和 1.0
UISlider *slider_ = (UISlider *)sender;
CGFloat ourSliderValue = slider_.value;
UIVisualEffectView *currentBlurObject =
[blurArray objectAtIndex:blurArray.count - 1];
currentBlurObject.alpha = ourSliderValue;
收缩展开的尺寸变化处理程序
int changeInWidth = 0; // one pixel at a time
if (pinchGesture.scale > 1.0) {
changeInWidth++;
}
if (pinchGesture.scale < 1.0) {
changeInWidth--;
}
UIVisualEffectView *currentBlurObject =
[blurArray objectAtIndex:blurArray.count - 1];
CGPoint oldCenter = currentBlurObject.center;
currentBlurObject.frame = CGRectMake(0, 0, currentBlurObject.frame.size.width + changeInWidth, currentBlurObject.frame.size.width + changeInWidth);
currentBlurObject.center = oldCenter;
lastChosenBlurCircleRect = currentBlurObject.frame;
CGFloat blurCornerRadius = currentBlurObject.frame.size.width/2;
[[currentBlurObject layer]setCornerRadius:blurCornerRadius];
为了使用模糊级别的模糊 - 使用下面我的扩展:
public extension UIView {
func applyBlur(level: CGFloat) {
let context = CIContext(options: nil)
self.makeBlurredImage(with: level, context: context, completed: { processedImage in
let imageView = UIImageView(image: processedImage)
imageView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(imageView)
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: self.topAnchor),
imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
])
})
}
private func makeBlurredImage(with level: CGFloat, context: CIContext, completed: @escaping (UIImage) -> Void) {
// screen shot
UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 1)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let resultImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
let beginImage = CIImage(image: resultImage)
// make blur
let blurFilter = CIFilter(name: "CIGaussianBlur")!
blurFilter.setValue(beginImage, forKey: kCIInputImageKey)
blurFilter.setValue(level, forKey: kCIInputRadiusKey)
// extend source image na apply blur to it
let cropFilter = CIFilter(name: "CICrop")!
cropFilter.setValue(blurFilter.outputImage, forKey: kCIInputImageKey)
cropFilter.setValue(CIVector(cgRect: beginImage!.extent), forKey: "inputRectangle")
let output = cropFilter.outputImage
var cgimg: CGImage?
var extent: CGRect?
let global = DispatchQueue.global(qos: .userInteractive)
global.async {
extent = output!.extent
cgimg = context.createCGImage(output!, from: extent!)!
let processedImage = UIImage(cgImage: cgimg!)
DispatchQueue.main.async {
completed(processedImage)
}
}
}
}
如何使用。 运行 如果视图已经完成,它会在框架时显示。例如在 viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
myView.applyBlur(level: 5)
}
非常感谢 mitja13,我制作了 Objective-C 版本。
NS_ASSUME_NONNULL_BEGIN
@interface UIView (Gaoding)
- (void)gd_pauseAnimationsWithDelay:(double)delay;
- (void)gd_resumeAnimations;
@end
NS_ASSUME_NONNULL_END
@implementation UIView (Gaoding)
- (void)gd_pauseAnimationsWithDelay:(double)delay {
double time = delay + CFAbsoluteTimeGetCurrent();
__block CALayer *layer = self.layer;
CFRunLoopRef runloopRef = CFRunLoopGetCurrent();
CFRunLoopAddTimer(runloopRef, CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, time, 0, 0, 0, ^(CFRunLoopTimerRef timer) {
double pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0;
layer.timeOffset = pausedTime;
layer = nil;
CFRunLoopRemoveTimer(runloopRef, timer, kCFRunLoopCommonModes);
CFRelease(timer);
timer = NULL;
}), kCFRunLoopCommonModes);
}
- (void)gd_resumeAnimations {
CALayer *layer = self.layer;
double pausedTime = layer.timeOffset;
layer.speed = 1;
layer.timeOffset = 0.0;
layer.beginTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
}
@end
如何使用:
/// SHOW IT
UIVisualEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *blurEffectView = UIVisualEffectView.new;
// .... something other
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
blurEffectView.effect = effect;
}];
[blurEffectView gd_pauseAnimationsWithDelay:0.1]; // 0.1/0.35 = 28.57% blur of UIBlurEffectStyleLight
// .... something other
/// HIDE IT
[blurEffectView gd_resumeAnimations];
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^{
blurEffectView.effect = nil;
}];
类似于@mitja13的解决方案,但使用UIViewPropertyAnimator
,稍微更简洁:
var animator: UIViewPropertyAnimator!
viewDidLoad() {
super.viewDidLoad()
let blurEffectView = UIVisualEffectView()
yourViewToBeBlurred.addSubview(blurEffectView)
blurEffectView.fillSuperview() // This my custom method that anchors to the superview using auto layout. Write your own
animator = UIViewPropertyAnimator(duration: 1, curve: .linear, animations: {
blurEffectView.effect = UIBlurEffect(style: .regular)
})
animator.fractionComplete = 0.6 // Adjust to the level of blur you want
}
标题几乎问了一切...
我正在玩 iOS8 Visual Effect View with Blur
。它位于显示用户可选择的背景照片的 UIImageView
上方。放置在contentView中的视图本身就是我自己的自定义视图,显示了一种graph/calendar。大部分所说的日历图是透明的。它应用于它后面的照片的模糊真的很重。我想让更多的细节泄露出去。但是Apple似乎只给出了三个罐装值:
typedef enum {
UIBlurEffectStyleExtraLight,
UIBlurEffectStyleLight,
UIBlurEffectStyleDark
} UIBlurEffectStyle;
我已经用 UIVisualEffectView
的不同 alpha 和背景颜色进行了修改(尽管文档警告不要这样做),但这只会让事情变得更糟。
模糊严重的原因是模糊效果样式影响图像的亮度级别,而不是应用的模糊量。
不幸的是,尽管 Apple 显然有能力以编程方式控制应用的模糊量——尝试在启动板上缓慢向下拖动以观看 Spotlight 模糊过渡——我没有看到任何 publicAPI 将模糊量传递给 UIBlurEffect
。
此 post 声称调整背景颜色 alpha 会增加模糊量。值得一试,但我看不到记录在哪里:
这对我有用。
在添加到我的视图之前,我将 UIVisualEffectView
放在 UIView
中。
我让这个功能更容易使用。您可以使用此功能模糊视图中的任何区域。
func addBlurArea(area: CGRect, style: UIBlurEffectStyle) {
let effect = UIBlurEffect(style: style)
let blurView = UIVisualEffectView(effect: effect)
let container = UIView(frame: area)
blurView.frame = CGRect(x: 0, y: 0, width: area.width, height: area.height)
container.addSubview(blurView)
container.alpha = 0.8
self.view.insertSubview(container, atIndex: 1)
}
例如,您可以通过调用以下命令使所有视图变得模糊:
addBlurArea(self.view.frame, style: UIBlurEffectStyle.Dark)
您可以将 Dark
更改为您想要的模糊样式,并将 0.8
更改为您想要的 alpha 值
遗憾的是Apple没有提供任何模糊效果的选项。但这个解决方法对我有用 - 动画模糊效果并在完成前暂停它。
func blurEffectView(enable enable: Bool) {
let enabled = self.blurView.effect != nil
guard enable != enabled else { return }
switch enable {
case true:
let blurEffect = UIBlurEffect(style: .ExtraLight)
UIView.animateWithDuration(1.5) {
self.blurView.effect = blurEffect
}
self.blurView.pauseAnimation(delay: 0.3)
case false:
self.blurView.resumeAnimation()
UIView.animateWithDuration(0.1) {
self.blurView.effect = nil
}
}
}
以及用于暂停(延迟)和恢复视图动画的 UIView 扩展
extension UIView {
public func pauseAnimation(delay 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(), fromLayer: nil)
layer.speed = 0.0
layer.timeOffset = pausedTime
})
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes)
}
public func resumeAnimation() {
let pausedTime = layer.timeOffset
layer.speed = 1.0
layer.timeOffset = 0.0
layer.beginTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime
}
}
您可以在图像上添加 UIBlurEffect。这样就可以了。
这是一个带有模糊效果的 UIImageView 示例。记得给 UIImageView 添加一个 Image。
调整模糊量 blurEffectView.alpha = 0.8(从 0 到 1)
import UIKit
class BlurEffectImageView: UIImageView {
override func awakeFromNib() {
super.awakeFromNib()
addBlurEffect()
}
private func addBlurEffect() {
let blurEffect = UIBlurEffect(style: .light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.alpha = 0.8
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
blurEffectView.translatesAutoresizingMaskIntoConstraints = false
addSubview(blurEffectView)
NSLayoutConstraint(item: blurEffectView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: blurEffectView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: blurEffectView, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: blurEffectView, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1.0, constant: 0).isActive = true
}
}
将 BlurEffectView 添加到视图的 alpha < 1 的视图
func addBlurEffectView() -> Void {
if !UIAccessibilityIsReduceTransparencyEnabled() {
let viewContainer = UIView()
viewContainer.frame = self.view.bounds
viewContainer.alpha = 0.5
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.layer.zPosition = -0.5;
blurEffectView.frame = self.view.bounds;
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
viewContainer.addSubview(blurEffectView)
self.view.addSubview(viewContainer)
self.view.sendSubview(toBack: viewContainer)
}
}
此答案基于
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
一种类似于此处的解决方案,但更简单,是使用 UIViewPropertyAnimator (iOS 10+) 并将其 fractionComplete
属性 设置为介于 0 和 1 之间的某个值。
// add blur view to image view
let imgBlur = UIVisualEffectView()
imgView.addSubview(imgBlur)
imgBlur.frame = imgView.bounds
// create animator to control blur strength
let imgBlurAnimator = UIViewPropertyAnimator()
imgBlurAnimator.addAnimations {
imgBlur.effect = UIBlurEffect(style: .dark)
}
// 50% blur
imgBlurAnimator.fractionComplete = 0.5
请注意,如果您打算根据平移手势、滚动视图、滑块等改变 fractionComplete
,您需要设置 pausesOnCompletion = true
(iOS 11+) .
我像这样使用 UIVisualEffectView 来获得可调整的模糊圆圈。模糊级别由控制 alpha 的滑块控制。我还将在下面包含滑块处理程序。模糊圆圈大小可通过捏张动作进行调整。我也会包括在内。您可以在模糊圆圈周围拖动。我将把它留作 reader 的练习。如果你想要一个模糊的矩形,只是不要圆角。要查看此模糊圆圈设计的实际效果,请加载 MemeSoEasy 应用程序(免费),添加一张照片(您可以在其上放置一个模糊圆圈),然后添加一个模糊圆圈。
UIVisualEffectView *blurVisualEffectView;
UIVisualEffect *blurEffect;
blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
blurVisualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
blurVisualEffectView.frame = lastChosenBlurCircleRect;
blurVisualEffectView.center = CGPointMake(halfScreenX, halfScreenY);
[self.view addSubview:blurVisualEffectView];
CGFloat blurCornerRadius = blurVisualEffectView.bounds.size.width/2;
[[blurVisualEffectView layer]setCornerRadius:blurCornerRadius];
[[blurVisualEffectView layer]setMasksToBounds:YES];
[[blurVisualEffectView layer] setBorderWidth:4.0f];
[[blurVisualEffectView layer] setBorderColor:[UIColor blueColor].CGColor];
blurVisualEffectView.userInteractionEnabled = NO;
blurVisualEffectView.alpha = 0.97;
[blurArray addObject:blurVisualEffectView];
滑块处理程序:
请注意,我将模糊对象存储在一个数组中,因此我可以让用户根据需要创建任意数量的对象。滑块处理程序处理数组中的最后一个对象。滑块最小值和最大值为 0.0 和 1.0
UISlider *slider_ = (UISlider *)sender;
CGFloat ourSliderValue = slider_.value;
UIVisualEffectView *currentBlurObject =
[blurArray objectAtIndex:blurArray.count - 1];
currentBlurObject.alpha = ourSliderValue;
收缩展开的尺寸变化处理程序
int changeInWidth = 0; // one pixel at a time
if (pinchGesture.scale > 1.0) {
changeInWidth++;
}
if (pinchGesture.scale < 1.0) {
changeInWidth--;
}
UIVisualEffectView *currentBlurObject =
[blurArray objectAtIndex:blurArray.count - 1];
CGPoint oldCenter = currentBlurObject.center;
currentBlurObject.frame = CGRectMake(0, 0, currentBlurObject.frame.size.width + changeInWidth, currentBlurObject.frame.size.width + changeInWidth);
currentBlurObject.center = oldCenter;
lastChosenBlurCircleRect = currentBlurObject.frame;
CGFloat blurCornerRadius = currentBlurObject.frame.size.width/2;
[[currentBlurObject layer]setCornerRadius:blurCornerRadius];
为了使用模糊级别的模糊 - 使用下面我的扩展:
public extension UIView {
func applyBlur(level: CGFloat) {
let context = CIContext(options: nil)
self.makeBlurredImage(with: level, context: context, completed: { processedImage in
let imageView = UIImageView(image: processedImage)
imageView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(imageView)
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: self.topAnchor),
imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
])
})
}
private func makeBlurredImage(with level: CGFloat, context: CIContext, completed: @escaping (UIImage) -> Void) {
// screen shot
UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 1)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let resultImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
let beginImage = CIImage(image: resultImage)
// make blur
let blurFilter = CIFilter(name: "CIGaussianBlur")!
blurFilter.setValue(beginImage, forKey: kCIInputImageKey)
blurFilter.setValue(level, forKey: kCIInputRadiusKey)
// extend source image na apply blur to it
let cropFilter = CIFilter(name: "CICrop")!
cropFilter.setValue(blurFilter.outputImage, forKey: kCIInputImageKey)
cropFilter.setValue(CIVector(cgRect: beginImage!.extent), forKey: "inputRectangle")
let output = cropFilter.outputImage
var cgimg: CGImage?
var extent: CGRect?
let global = DispatchQueue.global(qos: .userInteractive)
global.async {
extent = output!.extent
cgimg = context.createCGImage(output!, from: extent!)!
let processedImage = UIImage(cgImage: cgimg!)
DispatchQueue.main.async {
completed(processedImage)
}
}
}
}
如何使用。 运行 如果视图已经完成,它会在框架时显示。例如在 viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
myView.applyBlur(level: 5)
}
非常感谢 mitja13,我制作了 Objective-C 版本。
NS_ASSUME_NONNULL_BEGIN
@interface UIView (Gaoding)
- (void)gd_pauseAnimationsWithDelay:(double)delay;
- (void)gd_resumeAnimations;
@end
NS_ASSUME_NONNULL_END
@implementation UIView (Gaoding)
- (void)gd_pauseAnimationsWithDelay:(double)delay {
double time = delay + CFAbsoluteTimeGetCurrent();
__block CALayer *layer = self.layer;
CFRunLoopRef runloopRef = CFRunLoopGetCurrent();
CFRunLoopAddTimer(runloopRef, CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, time, 0, 0, 0, ^(CFRunLoopTimerRef timer) {
double pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0;
layer.timeOffset = pausedTime;
layer = nil;
CFRunLoopRemoveTimer(runloopRef, timer, kCFRunLoopCommonModes);
CFRelease(timer);
timer = NULL;
}), kCFRunLoopCommonModes);
}
- (void)gd_resumeAnimations {
CALayer *layer = self.layer;
double pausedTime = layer.timeOffset;
layer.speed = 1;
layer.timeOffset = 0.0;
layer.beginTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
}
@end
如何使用:
/// SHOW IT
UIVisualEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *blurEffectView = UIVisualEffectView.new;
// .... something other
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
blurEffectView.effect = effect;
}];
[blurEffectView gd_pauseAnimationsWithDelay:0.1]; // 0.1/0.35 = 28.57% blur of UIBlurEffectStyleLight
// .... something other
/// HIDE IT
[blurEffectView gd_resumeAnimations];
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^{
blurEffectView.effect = nil;
}];
类似于@mitja13的解决方案,但使用UIViewPropertyAnimator
,稍微更简洁:
var animator: UIViewPropertyAnimator!
viewDidLoad() {
super.viewDidLoad()
let blurEffectView = UIVisualEffectView()
yourViewToBeBlurred.addSubview(blurEffectView)
blurEffectView.fillSuperview() // This my custom method that anchors to the superview using auto layout. Write your own
animator = UIViewPropertyAnimator(duration: 1, curve: .linear, animations: {
blurEffectView.effect = UIBlurEffect(style: .regular)
})
animator.fractionComplete = 0.6 // Adjust to the level of blur you want
}