UIVisualEffectView doesn't blur it's SKView superview

牧云@^-^@ 提交于 2019-12-07 10:28:20

问题


I'm writing a SpriteKit game and faced a problem with blurred view, which lies on the SKView. It is supposed to slide from the right when game is paused and it should blur the content of it's parent view (SKView) just like control center panel in iOS 7. Here is the desired appearance:

What I actually get is:

In fact the view on the left is not totally black, you can see how highlights from the superview are slightly struggling through almost opaque subview, but no blur is applied. Is it an iOS 8 bug/feature, or is it my mistake/misunderstanding

Here is my UIVisualEffectView subclass's essensials:

class OptionsView: UIVisualEffectView {
//...
    init(size: CGSize) {
        buttons = [UIButton]()
        super.init(effect: UIBlurEffect(style: .Dark))
        frame = CGRectMake(-size.width, 0, size.width, size.height)
        addButtons()
        clipsToBounds = true
    }
    func show() {
        UIView.animateWithDuration(0.3, animations: {
            self.frame.origin.x = 0
        })
    }
    func hide() {
        UIView.animateWithDuration(0.3, animations: {
            self.frame.origin.x = -self.frame.size.width
        })
    }

Then in GameScene class:

in initializer:

optionsView = OptionsView(size: CGSizeMake(130, size.height))

in didMoveToView(view: SKView):

view.addSubview(optionsView)

on pressing pause button:

self.optionsView.show()

P.S. Though I know two another ways to implement blur view, I thought this one was the easiest, since my app is going to support iOS8 only

  1. Render a blurred static image from superview -> put UIImageView on the OptionsView, with clipsToBounds = true -> animate UIImageView position while animating optionsView position, so that blur stays still relatively to the superview

  2. Forget about UIView, UIVisualEffectView and UIBlurView and use SKEffectNode together with SKCropNode.


回答1:


Ok, I have managed to get the desired effect using SKEffectNode instead of UIVisualEffectView. Here is the code for someone facing the same issue

class BlurCropNode: SKCropNode {
    var blurNode: BlurNode
    var size: CGSize
    init(size: CGSize) {
        self.size = size
        blurNode = BlurNode(radius: 10)
        super.init()
        addChild(blurNode)
        let mask = SKSpriteNode (color: UIColor.blackColor(), size: size)
        mask.anchorPoint = CGPoint.zeroPoint
        maskNode = mask
    }
}

class BlurNode: SKEffectNode {
    var sprite: SKSpriteNode
    var texture: SKTexture {
        get { return sprite.texture }
        set {
            sprite.texture = newValue
            let scale = UIScreen.mainScreen().scale
            let textureSize = newValue.size()
            sprite.size = CGSizeMake(textureSize.width/scale, textureSize.height/scale)
        }
    }
    init(radius: CGFloat) {
        sprite = SKSpriteNode()
        super.init()
        sprite.anchorPoint = CGPointMake(0, 0)
        addChild(sprite)
        filter = CIFilter(name: "CIGaussianBlur", withInputParameters: ["inputRadius": radius])
        shouldEnableEffects = true
        shouldRasterize = true
    }
}

Result:

There are several issues though

  1. Cropping doesn't work with SKEffectNode until it's shouldRasterize property is set to true. I get the whole screen blurred. So I still don't know how to properly implement realtime blur.

  2. Animation on the BlurCropNode is not smooth enough. There is a lag at the beginning because of capturing texture and setting it to the effectNode's sprite child. Even dispatch_async doesn't help.

It would be very much appreciated if anyone could help to solve at least one of the problems




回答2:


I know I'm probably a bit late but I was having the same problem and found a solution to creating a realtime blur on part of the screen. It's based on this tutorial: http://www.youtube.com/watch?v=eYHId0zgkdE where he used a shader to blur a static sprite. I extended his tutorial to capture of the part of the screen and then apply the blur to that. For your problem you could capture under that sidebar.

Firstly, you create an SKSpriteNode to hold the captured texture. Then in didMoveToView() you add your blur shader to that sprite. (You can find the blur.fsh file on GitHub, there's a link at the bottom of the youtube video.)

override func didMoveToView(view: SKView) {
    blurNode.shader = SKShader(fileNamed: "blur")

    self.addChild(blurNode)
}

Then you have to capture the section of the view you want to blur and apply the SKTexture to, in my case, blurNode.

override func update(currentTime: CFTimeInterval) {
    // Hide the blurNode to avoid it be captured too.
    blurNode.hidden = true
    blurNode.texture = self.view!.textureFromNode(self, crop: blurNode.frame)
    blurNode.hidden = false
}

And that should be it. On my iPad mini, with a blur of 1/3 of the width of the screen, the fps was 58-59. Blurring the whole screen the fps was down to about 22 so it's obviously not ideal for some things but hopefully it helps.



来源:https://stackoverflow.com/questions/24980353/uivisualeffectview-doesnt-blur-its-skview-superview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!