Swift 如何设置UIBlurEffectStyle.Light的模糊半径

Swift 如何设置UIBlurEffectStyle.Light的模糊半径,swift,uiblureffect,Swift,Uiblureffect,我想知道如何设置iOS newUIBlurEffectStyle.Light的半径/模糊因子?我在文档中找不到任何东西。但是我希望它看起来像经典的UIImage+ImageEffects.hblur效果 required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) let blur = UIBlurEffect(style: UIBlurEffectStyle.Light) let ef

我想知道如何设置iOS new
UIBlurEffectStyle.Light的半径/模糊因子?我在文档中找不到任何东西。但是我希望它看起来像经典的
UIImage+ImageEffects.h
blur效果

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    
    let blur = UIBlurEffect(style: UIBlurEffectStyle.Light)
    let effectView = UIVisualEffectView(effect: blur)
    effectView.frame = frame
    addSubview(effectView)
}

恐怕目前还没有这样的api。按照苹果的做事方式,新功能总是伴随着限制而来,而且功能会逐渐显现出来。也许这在iOS 9或iOS 10上是可能的…

尽管这是一种黑客行为,可能不会被应用商店接受,但仍然是可能的。您必须将
UIBlurEffect
子类化,如下所示:

#import <objc/runtime.h>

@interface UIBlurEffect (Protected)
@property (nonatomic, readonly) id effectSettings;
@end

@interface MyBlurEffect : UIBlurEffect
@end

@implementation MyBlurEffect

+ (instancetype)effectWithStyle:(UIBlurEffectStyle)style
{
    id result = [super effectWithStyle:style];
    object_setClass(result, self);

    return result;
}

- (id)effectSettings
{
    id settings = [super effectSettings];
    [settings setValue:@50 forKey:@"blurRadius"];
    return settings;
}

- (id)copyWithZone:(NSZone*)zone
{
    id result = [super copyWithZone:zone];
    object_setClass(result, [self class]);
    return result;
}

@end
#导入
@界面效果(受保护)
@属性(非原子,只读)id设置;
@结束
@界面MyBlurEffect:UIBlurEffect
@结束
@实施效果
+(instancetype)effectWithStyle:(UIBlurEffectStyle)样式
{
id结果=[super effectWithStyle:style];
对象设置类(结果、自身);
返回结果;
}
-(id)效果设置
{
id设置=[super effectSettings];
[设置设置值:@50 forKey:@blurRadius];
返回设置;
}
-(id)copyWithZone:(NSZone*)区
{
id结果=[super copyWithZone:zone];
对象_setClass(结果,[self class]);
返回结果;
}
@结束
这里模糊半径设置为50。您可以将50更改为所需的任何值


然后在为
UIVisualEffectView
创建效果时,只需使用
MyBlurEffect
类而不是
UIBlurEffect
,就可以更改添加模糊效果的UIVisualEffectView的alpha

let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.Light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.alpha = 0.5
blurEffectView.frame = self.view.bounds
self.view.addSubview(blurEffectView)

这不是一个真正的解决方案,因为它实际上不会改变模糊的半径,但我发现它只需很少的工作就可以完成任务。

如果你想实现与iOS spotlight search相同的行为,你只需要更改UIVisualEffectView(在iOS9模拟器上测试)的alpha值。

这对我很有效

在添加到我的视图之前,我将
UIVisualEffectView
放在
UIView

我使这个函数更容易使用。您可以使用此功能模糊视图中的任何区域

func addBlurArea(area: CGRect) {
    let effect = UIBlurEffect(style: UIBlurEffectStyle.Dark)
    let blurView = UIVisualEffectView(effect: effect)
    blurView.frame = CGRect(x: 0, y: 0, width: area.width, height: area.height)

    let container = UIView(frame: area)
    container.alpha = 0.8
    container.addSubview(blurView)

    self.view.insertSubview(container, atIndex: 1)
}
例如,您可以通过调用以下命令来模糊所有视图:

addBlurArea(self.view.frame)

您可以将
Dark
更改为所需的模糊样式,将
0.8
更改为所需的alpha值

最近开发的
bluur
库动态更改
UIVisualEffectsView
的模糊半径,而无需使用任何专用API:

它使用设置
效果
的暂停动画来实现改变模糊半径。基于此要点的解决方案:

其主要思想是:

// Freeze animation
blurView.layer.speed = 0;

blurView.effect = nil;
[UIView animateWithDuration:1.0 animations:^{
    blurView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
}];

// Set animation progress from 0 to 1
blurView.layer.timeOffset = 0.5;
更新:


苹果在iOS 10中引入了类。这正是我们为
UIVisualEffectsView
.effect
属性设置动画所需要的。希望社区能够将此功能移植到以前的iOS版本。

目前我没有找到任何解决方案。
顺便说一句,您可以添加一点技巧,让模糊遮罩不那么“模糊”,方法如下:

let blurView = .. // here create blur view as usually

if let blurSubviews = self.blurView?.subviews {
    for subview in blurSubviews {
        if let filterView = NSClassFromString("_UIVisualEffectFilterView") {
            if subview.isKindOfClass(filterView) {
                subview.hidden = true
            }
        }
    }
}

改变alpha并不是一个完美的解决方案。它不影响模糊强度。您可以将动画从
nil
设置为目标模糊效果,并手动设置时间偏移以获得所需的模糊强度。不幸的是,当应用程序从后台返回时,iOS将重置动画偏移

谢天谢地,有一个简单的解决方案可以在iOS>=10上运行。您可以使用
UIViewPropertyAnimator
。我没有注意到使用它有任何问题。当应用程序从背景返回时,我保持自定义模糊强度。以下是您如何实现它:

class CustomIntensityVisualEffectView: UIVisualEffectView {

    /// Create visual effect view with given effect and its intensity
    ///
    /// - Parameters:
    ///   - effect: visual effect, eg UIBlurEffect(style: .dark)
    ///   - intensity: custom intensity from 0.0 (no effect) to 1.0 (full effect) using linear scale
    init(effect: UIVisualEffect, intensity: CGFloat) {
        super.init(effect: nil)
        animator = UIViewPropertyAnimator(duration: 1, curve: .linear) { [unowned self] in self.effect = effect }
        animator.fractionComplete = intensity
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }

    // MARK: Private
    private var animator: UIViewPropertyAnimator!

}

我还创建了一个要点:

这是完全可行的。使用
CoreImage
模块中的
CIFilter
自定义模糊半径。事实上,您甚至可以通过连续变化(也称为渐变)模糊半径()实现模糊效果


在尝试了上述解决方案后,我突然想到了这个想法,虽然有点老套,但我还是成功了。因为我们不能修改默认的半径设置为“50”,所以我们可以放大它并缩小它

previewView.snp.makeConstraints { (make) in
    make.centerX.centerY.equalTo(self.view)
    make.width.height.equalTo(self.view).multipliedBy(4)
}

previewBlur.snp.makeConstraints { (make) in
    make.edges.equalTo(previewView)
}
然后呢,

previewView.transform = CGAffineTransform(scaleX: 0.25, y: 0.25)
previewBlur.transform = CGAffineTransform(scaleX: 0.25, y: 0.25)

我得到了12.5的模糊半径。希望这对iOS 11有所帮助:-)

在viewDidLoad()中


有一种未记录的方法可以做到这一点。不一定推荐,因为它可能会让你的应用被苹果拒绝。但它确实有效

if let blurEffectType = NSClassFromString("_UICustomBlurEffect") as? UIBlurEffect.Type {
        let blurEffectInstance = blurEffectType.init()

        // set any value you want here. 40 is quite blurred 
        blurEffectInstance.setValue(40, forKey: "blurRadius")
        let effectView: UIVisualEffectView = UIVisualEffectView(effect: blurEffectInstance)

        // Now you have your blurred visual effect view
    }

我有这个问题的最终解决办法:

fileprivate final class UIVisualEffectViewInterface {
func setIntensity(effectView: UIVisualEffectView, intensity: CGFloat){
    let effect = effectView.effect
    effectView.effect = nil
    animator = UIViewPropertyAnimator(duration: 1, curve: .linear) { [weak effectView] in effectView?.effect = effect }
    animator.fractionComplete = intensity
}

private var animator: UIViewPropertyAnimator! }



extension UIVisualEffectView{
private var key: UnsafeRawPointer? { UnsafeRawPointer(bitPattern: 16) }

private var interface: UIVisualEffectViewInterface{
    if let key = key, let visualEffectViewInterface = objc_getAssociatedObject(self, key) as? UIVisualEffectViewInterface{
        return visualEffectViewInterface
    }
    let visualEffectViewInterface = UIVisualEffectViewInterface()
    
    if let key = key{
        objc_setAssociatedObject(self, key, visualEffectViewInterface, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
    }
    return visualEffectViewInterface
}

func intensity(_ value: CGFloat){
    interface.setIntensity(effectView: self, intensity: value)
}}

对。我的意思是,我们以前甚至没有UIVisualEffect视图,所以情况正在慢慢改善。您好,2016年开始。iOS 9.2已经发布,但仍然没有发布。iOS 10?还是没有’_(ツ)_/'IOS11?或z==3iOS12?仍然没有'\_(ツ)_/''我发誓他们在联盟的平台州宣布您可以修改blurRadius!但我找不到任何文档!此解决方案不起作用。更改blurRadius后发生错误:
malloc:**对象0x7fbf9969b690的错误:释放对象的校验和不正确-对象可能在释放后被修改***在malloc\u error\u break中设置断点以调试
如果按照答案中所写的方式进行操作,则可以完美地完成此操作。如果在将BlurEffect添加到效果视图后修改模糊半径,则说明您做错了。在添加过程中复制了BlurEffect,并且您正在修改的实例未被EffectView使用。是否只有一个采用此方法nswer并在应用商店中被接受?这是可行的,但它不会显示模糊半径的逐渐变化,比如说,从半径1到5或10…(至少在模拟器中)虽然没有解决核心问题,但这确实是一个很好的解决方法,并且更有可能被应用到应用商店中!很好。使用UIVisualEffectView类时,请避免小于1的alpha值。创建部分透明的视图会导致系统在关闭期间合并视图和所有关联子视图Screen render pass.UIVisualEffectView对象需要作为内容的一部分进行组合,这些对象是分层的
if let blurEffectType = NSClassFromString("_UICustomBlurEffect") as? UIBlurEffect.Type {
        let blurEffectInstance = blurEffectType.init()

        // set any value you want here. 40 is quite blurred 
        blurEffectInstance.setValue(40, forKey: "blurRadius")
        let effectView: UIVisualEffectView = UIVisualEffectView(effect: blurEffectInstance)

        // Now you have your blurred visual effect view
    }
fileprivate final class UIVisualEffectViewInterface {
func setIntensity(effectView: UIVisualEffectView, intensity: CGFloat){
    let effect = effectView.effect
    effectView.effect = nil
    animator = UIViewPropertyAnimator(duration: 1, curve: .linear) { [weak effectView] in effectView?.effect = effect }
    animator.fractionComplete = intensity
}

private var animator: UIViewPropertyAnimator! }



extension UIVisualEffectView{
private var key: UnsafeRawPointer? { UnsafeRawPointer(bitPattern: 16) }

private var interface: UIVisualEffectViewInterface{
    if let key = key, let visualEffectViewInterface = objc_getAssociatedObject(self, key) as? UIVisualEffectViewInterface{
        return visualEffectViewInterface
    }
    let visualEffectViewInterface = UIVisualEffectViewInterface()
    
    if let key = key{
        objc_setAssociatedObject(self, key, visualEffectViewInterface, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
    }
    return visualEffectViewInterface
}

func intensity(_ value: CGFloat){
    interface.setIntensity(effectView: self, intensity: value)
}}