web-dev-qa-db-ja.com

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.
}

それらのどれも動作しません。

30
Johan Enstam

@theMonsterの提案の後に、コメントを投稿します。

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

ストーリーボードで、ユーザー定義のランタイム属性に2つのパラメーターを追加しますlayer.cornerRadius = 8およびlayer.masksToBounds = true

またはコードで

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

既存のソリューションはすべて完璧ではありません。

UIVisualEffectViewは、2つのサブビューコンテンツを合成することで視覚効果を実装します。1つは背景ビューで、もう1つはフィルタービューです。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

5
WeZZard

サブクラス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
the Reverend