UIVisualEffectView上的角半径

时间:2015-03-13 09:59:16

标签: swift xcode6 cornerradius uivisualeffectview

嗨我想知道是否可以在UIVisualEffectView上设置转角半径? 这是我尝试过的代码:

@IBOutlet var blurView: UIVisualEffectView!

var blurLayer : CALayer{
    return blurView.layer
}
override func viewDidLoad() {
    super.viewDidLoad()
    setUpLayer()
    // Do any additional setup after loading the view.
}

func setUpLayer(){
    blurLayer.cornerRadius = 50
}

@IBOutlet var blurView: UIVisualEffectView!

override func viewDidLoad() {
    super.viewDidLoad()
    blurView.layer.cornerRadius = 50
    // Do any additional setup after loading the view.
}

非他们的作品。

4 个答案:

答案 0 :(得分:51)

在@theMonster建议之后,我发布的是评论。

override func viewDidLoad() {
    super.viewDidLoad()
    blurView.layer.cornerRadius = 50
    blurView.clipsToBounds = true
}

答案 1 :(得分:4)

所有现有的解决方案并不完美。

由于UIVisualEffectView通过合成两个子视图内容来实现其视觉效果 - 一个是背景视图,另一个是过滤视图,当您通过屏蔽整个UIVisualEffectView来实现您的角半径时,那里角落周围会有一些肮脏的颜色。

Dirty Colors Around Corners

要摆脱这些肮脏的颜色,你只需要屏蔽UIVisualEffects的过滤视图。

private typealias ObjcRawUIVisualEffectViewSelCGRect =
    @convention(c) (UIVisualEffectView, Selector, CGRect) -> Void

private var cornerRadiusKey =
"com.WeZZard.Waxing.UIVisualEffectView-CornerRadius.cornerRadius"

private var needsUpdateMaskLayerKey =
"com.WeZZard.Waxing.UIVisualEffectView-CornerRadius.needsUpdateMaskLayer"

extension UIVisualEffectView {
    public var cornerRadius: CGFloat {
        get {
            if let storedValue = objc_getAssociatedObject(self,
                &cornerRadiusKey)
                as? CGFloat
            {
                return storedValue
            }
            return 0
        }
        set {
            if cornerRadius != newValue {
                objc_setAssociatedObject(self,
                    &cornerRadiusKey,
                    newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
                setNeedsUpdateMaskLayer()
            }
        }
    }

    private var needsUpdateMaskLayer: Bool {
        get {
            if let storedValue = objc_getAssociatedObject(self,
                &needsUpdateMaskLayerKey)
                as? Bool
            {
                return storedValue
            }
            return false
        }
        set {
            objc_setAssociatedObject(self,
                &needsUpdateMaskLayerKey,
                newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }


    public override class func initialize() {
        swizzle_setBounds()
    }

    private class func swizzle_setBounds() {
        struct Static {
            static var token: dispatch_once_t = 0
        }

        dispatch_once(&Static.token) {
            let selector: Selector = "setBounds:"

            let method = class_getInstanceMethod(self, selector)

            let imp_original = method_getImplementation(method)

            before_setBounds = unsafeBitCast(imp_original,
                ObjcRawUIVisualEffectViewSelCGRect.self)

            class_replaceMethod(self,
                selector,
                unsafeBitCast(after_setBounds, IMP.self),
                "@:{_struct=CGRect}")
        }
    }

    private func setNeedsUpdateMaskLayer() {
        needsUpdateMaskLayer = true
        NSOperationQueue.mainQueue().addOperationWithBlock { [weak self] _ in
            self?.updateMaskLayerIfNeeded()
        }
    }

    private func updateMaskLayerIfNeeded() {
        if needsUpdateMaskLayer {
            updateMaskLayer()
            needsUpdateMaskLayer = false
        }
    }

    private func updateMaskLayer(){
        var filterViewFound = false
        for each in subviews {
            if each.dynamicType.description()
                .containsString("Filter")
            {
                filterViewFound = true
                let newPath = UIBezierPath(roundedRect: each.bounds,
                    cornerRadius: self.cornerRadius)
                    .CGPath
                if let existedMask = each.layer.mask
                    as? CAShapeLayer
                {
                    existedMask.path = newPath
                } else {
                    let shapeLayer = CAShapeLayer()
                    shapeLayer.path = newPath
                    each.layer.mask = shapeLayer
                }
            } else {
                setNeedsUpdateMaskLayer()
            }
        }
        assert(filterViewFound == true, "Filter view was not found! Check your hacking!")
    }
}

private var before_setBounds: ObjcRawUIVisualEffectViewSelCGRect = { _ in
    fatalError("No implementation found")
}

private let after_setBounds: ObjcRawUIVisualEffectViewSelCGRect = {
    (aSelf, selector, bounds) -> Void in

    let oldBounds = aSelf.bounds

    before_setBounds(aSelf, selector, bounds)

    if oldBounds.size != bounds.size {
        aSelf.setNeedsUpdateMaskLayer()
    }
}

所有事情都已完成!

Without Dirty Colors

答案 2 :(得分:3)

子类UIVisualEffectView

class PSORoundedVisualEffectView : UIVisualEffectView{

    override func layoutSubviews() {
        super.layoutSubviews()
        updateMaskLayer()
    }

    func updateMaskLayer(){
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: 10).CGPath
        self.layer.mask = shapeLayer
    }
}

将UIBezierPath替换为您想要的任何形状。

答案 3 :(得分:2)

在故事板上,在用户定义的运行时属性layer.cornerRadius = 8layer.masksToBounds = true中添加两个参数

或使用代码

@IBOutlet var blurView: UIVisualEffectView! {
    didSet {
        blurView.layer.cornerRadius = 8
        blurView.layer.masksToBounds = true
    }
}