ios 使用“带有模糊的视觉效果视图”减少模糊?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29498884/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Less Blur with `Visual Effect View with Blur`?
提问by Travis Griggs
Title pretty much asks it all...
标题几乎问了一切......
I'm playing with the iOS8 Visual Effect View with Blur
. It's over a UIImageView
that shows a user choosable background photo. The view placed in the contentView itself is my own custom view, shows a sort of graph/calendar. Most of said calendar graph is transparent. The blur it applies to the photo behind it is really heavy. I'd like to let more of the detail leak through. But Apple only seems to give three canned values:
我正在玩 iOS8 Visual Effect View with Blur
。它结束了UIImageView
显示用户可选择的背景照片。放置在 contentView 本身中的视图是我自己的自定义视图,显示了一种图表/日历。大多数所说的日历图是透明的。它适用于它背后的照片的模糊真的很重。我想让更多的细节泄露出去。但苹果似乎只给出了三个预设值:
typedef enum {
UIBlurEffectStyleExtraLight,
UIBlurEffectStyleLight,
UIBlurEffectStyleDark
} UIBlurEffectStyle;
I've monkied around with different alphas and background colors of the UIVisualEffectView
(even though the documentation warns against that), but that doesn't do anything but make it worse.
我已经使用了不同的 alpha 和背景颜色UIVisualEffectView
(即使文档对此提出警告),但这并没有做任何事情,只会让情况变得更糟。
回答by mitja13
It's a pity that Apple did not provide any options for blur effect. But this workaround worked for me - animating the blur effect and pausing it before completion.
遗憾的是,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
}
}
}
and the UIView extensions for pausing (with a delay) and resuming view's animation
以及用于暂停(延迟)和恢复视图动画的 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
}
}
回答by StilesCrisis
The reason you're getting heavy blur is that the blur effect style affects the brightnesslevel of the image, not the amount of blur applied.
出现严重模糊的原因是模糊效果样式会影响图像的亮度级别,而不是应用的模糊量。
Unfortunately, although Apple clearly has the ability to control the amount of blur applied programmatically--try dragging down slowly on the launchpad to watch the Spotlight blurring transition--I don't see any public API to pass a blur amount to UIBlurEffect
.
不幸的是,虽然 Apple 显然有能力控制以编程方式应用的模糊量——尝试在启动板上缓慢拖动以观看 Spotlight 模糊过渡——但我没有看到任何公共 API 将模糊量传递给UIBlurEffect
.
This post claims that adjusting the background color alpha will drive the blur amount. It's worth a try, but I don't see where that is documented: How to fade a UIVisualEffectView and/or UIBlurEffect in and out?
这篇文章声称调整背景颜色 alpha 将驱动模糊量。值得一试,但我没有看到记录在哪里:如何淡入淡出 UIVisualEffectView 和/或 UIBlurEffect?
回答by Demilitarized Zone
This works for me.
这对我有用。
I put UIVisualEffectView
in an UIView
before add to my view.
我把UIVisualEffectView
在UIView
添加到我的观点之前。
I make this function to use easier. You can use this function to make blur any area in your view.
我让这个功能更容易使用。您可以使用此功能模糊视图中的任何区域。
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)
}
For example, you can make blur all of your view by calling:
例如,您可以通过调用使所有视图变得模糊:
addBlurArea(self.view.frame, style: UIBlurEffectStyle.Dark)
You can change Dark
to your desired blur style and 0.8
to your desired alpha value
您可以更改Dark
为所需的模糊样式和0.8
所需的 alpha 值
回答by alegelos
You can add a UIBlurEffect over the image. And that will do the trick.
您可以在图像上添加 UIBlurEffect。这将解决问题。
Here is an example of a UIImageView with blur effect on it. Remember to add a Image to the UIImageView.
这是一个带有模糊效果的 UIImageView 示例。记得给 UIImageView 添加一个 Image。
Adjust blur amount with blurEffectView.alpha = 0.8 (from 0 to 1)
使用 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
}
}
回答by pinch
A solution similar to some here, but simpler, is to use a UIViewPropertyAnimator (iOS 10+) and set its fractionComplete
property to some value between 0 and 1.
类似于这里的一些但更简单的解决方案是使用 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
Note, if you plan to vary fractionComplete
based on a pan gesture, scroll view, slider, etc. you'll want to set pausesOnCompletion = true
(iOS 11+).
请注意,如果您打算fractionComplete
根据平移手势、滚动视图、滑块等进行更改,则需要设置pausesOnCompletion = true
(iOS 11+)。
回答by user3408691
I use UIVisualEffectView like this to get adjustable blur circles. The blur level is controlled by a slider that controls the alpha. I'll include the slider handler below too. The blur circle size is adjustable with pinch spread action. I will include that too. And you can drag around the blur circles. I'll leave that as an exercise for the reader. If you want a blur rectangle, just don't round the corners. To see this blur circle design in action, load the MemeSoEasy app (free), add a photo (that you can put a blur circle on top of), then add a blur circle.
我像这样使用 UIVisualEffectView 来获得可调整的模糊圆圈。模糊级别由控制 alpha 的滑块控制。我也会在下面包含滑块处理程序。模糊圆圈大小可通过捏散动作进行调节。我也会包括在内。您可以在模糊圆圈周围拖动。我将把它留给读者作为练习。如果你想要一个模糊的矩形,只是不要圆角。要查看此模糊圆圈设计的实际效果,请加载 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];
Slider handler :
滑块处理程序:
Note that I store my blur objects in an array, so I can let users create as many as desired. The slider handler works on the last object in the array. The slider min and max values are 0.0 and 1.0
请注意,我将模糊对象存储在一个数组中,因此我可以让用户创建任意数量的对象。滑块处理程序处理数组中的最后一个对象。滑块最小值和最大值分别为 0.0 和 1.0
UISlider *slider_ = (UISlider *)sender;
CGFloat ourSliderValue = slider_.value;
UIVisualEffectView *currentBlurObject =
[blurArray objectAtIndex:blurArray.count - 1];
currentBlurObject.alpha = ourSliderValue;
Size change handler for pinch spread
用于夹点传播的尺寸更改处理程序
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];
回答by Tà Truhoada
Add a BlurEffectView to a view with view's alpha < 1
将 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)
}
}
回答by James Jordan Taylor
This answer is based on Mitja Semolic's excellent earlier answer. I've converted it to swift 3, added an explanation to what's happening in coments, made it an extension of a UIViewController so any VC can call it at will, added an unblurred view to show selective application, and added a completion block so that the calling view controller can do whatever it wants at the completion of the blur.
这个答案基于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
}
}
I've confirmed that it works with both iOS 10.3.1 and iOS 11
我已经确认它适用于 iOS 10.3.1 和 iOS 11
回答by Leonif
In order to use blur with level of blur - use my extension below:
为了使用模糊级别的模糊 - 在下面使用我的扩展名:
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)
}
}
}
}
How to use. Run it when frame if view already done. For example in viewDidAppear:
如何使用。如果视图已经完成,则在框架时运行它。例如在 viewDidAppear 中:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
myView.applyBlur(level: 5)
}
回答by Quanhua Guan
HUGE THANKS TO mitja13, I make the Objective-CVersion.
非常感谢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
How to Use:
如何使用:
/// 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;
}];