Угловой радиус в 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.
}

Ни один из них не работает.


person Johan Enstam    schedule 13.03.2015    source источник
comment
Вы пробовали «blurView.clipsToBounds = true»?   -  person Mike M    schedule 13.03.2015
comment
Спасибо сработало как шарм!   -  person Johan Enstam    schedule 13.03.2015
comment
@MikeM Возможно, вам следует включить это в ответ?   -  person Oxcug    schedule 26.07.2015


Ответы (4)


После предложения @theMonster я публикую то, что было комментарием.

override func viewDidLoad() {
    super.viewDidLoad()
    blurView.layer.cornerRadius = 50
    blurView.clipsToBounds = true
}
person Mike M    schedule 26.07.2015

в раскадровке добавить два параметра в пользовательские атрибуты времени выполнения layer.cornerRadius = 8 и layer.masksToBounds = true

или в коде

@IBOutlet var blurView: UIVisualEffectView! {
    didSet {
        blurView.layer.cornerRadius = 8
        blurView.layer.masksToBounds = true
    }
}
person amir sheibani    schedule 16.07.2018
comment
Вам следует отредактировать этот ответ и исправить форматирование. Трудно понять, что такое объяснение, а что код. - person ; 16.07.2018

Подкласс 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 любой формой, которую вы хотите.

person the Reverend    schedule 25.07.2015
comment
Спасибо! Это работает очень хорошо. Но было бы проще просто сделать расширение. - person Henry Ngan; 23.04.2016
comment
Не правда ли, так проще - person Fattie; 06.09.2019

Все существующие решения не идеальны.

Поскольку UIVisualEffectView реализует свои визуальные эффекты путем компоновки содержимого двух подпредставлений — одно является фоновым представлением, а другое — представлением фильтра, когда вы реализуете свой угловой радиус, маскируя весь UIVisualEffectView, вокруг углов будут некоторые грязные цвета.

Грязные цвета по углам

Чтобы избавиться от этих грязных цветов, вам просто нужно замаскировать представление фильтра 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()
    }
}

И все дела сделаны!

Без грязных красок

person WeZZard    schedule 16.11.2015