• Xcode 7.2
  • swift 2

  • 我正在尝试用所谓的“BlurFilterMask”覆盖图像。这是我用Swift代码动态添加的CALayer,这是BlurFilterMask:
    class BlurFilterMask : CALayer {
    
        private let GRADIENT_WIDTH : CGFloat = 50.0
    
        var origin : CGPoint = CGPointZero {
            didSet {
                setNeedsDisplay()
            }
        }
    
        var diameter : CGFloat = 50.0 {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override init() {
            super.init()
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func drawInContext(ctx: CGContext) {
             CGContextSaveGState(ctx)
    
            let clearRegionRadius : CGFloat  = self.diameter * 0.5
            let blurRegionRadius : CGFloat  = clearRegionRadius + GRADIENT_WIDTH
    
            let baseColorSpace = CGColorSpaceCreateDeviceRGB();
            let colours : [CGFloat] = [0.0, 0.0, 0.0, 0.0,     // Clear region
            0.0, 0.0, 0.0, 0.6] // blur region color
            let colourLocations : [CGFloat] = [0.0, 0.0]
            let gradient = CGGradientCreateWithColorComponents (baseColorSpace, colours, colourLocations, 2)
    
    
            CGContextDrawRadialGradient(ctx, gradient, self.origin, clearRegionRadius, self.origin, blurRegionRadius, .DrawsAfterEndLocation);
    
        }
    
    }
    

    在我的UIViewController.viewDidLoad()中,我调用addMaskOverlay(),这是实现:
     func addMaskOverlay(){
            let blurFilterMask = BlurFilterMask()
    
            blurFilterMask.diameter = 80
            blurFilterMask.frame = heroImageView.bounds
            blurFilterMask.origin = heroImageView.center
            blurFilterMask.shouldRasterize = true
    
            heroImageView.layer.addSublayer(blurFilterMask)
    
            blurFilterMask.setNeedsDisplay()
        }
    

    例如,无论我使用什么模拟器,无论是iPhone 5还是iPhone 6或iPad 2,我总会得到相同的中心,宽度和高度:
  • print(heroImageView.center)=(300.0,67.5)
  • 打印(CGRectGetWidth(heroImageView.bounds))= 600.0
  • print(CGRectGetHeight(heroImageView.bounds))//135.0

  • 但是我的BlurFilterMask的中心总是有所不同,具体取决于设备模拟器,并且它永远不会从UIImageView的中心开始,例如iPhone 5:

    ios - 添加以UIImageView为中心的CALayer子层-LMLPHP

    这是iPhone 6:

    ios - 添加以UIImageView为中心的CALayer子层-LMLPHP

    我以为也许我需要在CALayer BlurFilterMask上垂直居中和水平居中约束,所以我尝试添加约束:
    heroImageView.layer.addSublayer(blurFilterMask)
    
    let xConstraint = NSLayoutConstraint(item: blurFilterMask, attribute: .CenterX, relatedBy: .Equal, toItem: heroImageView, attribute: .CenterX, multiplier: 1, constant: 0)
    
    let yConstraint = NSLayoutConstraint(item: blurFilterMask, attribute: .CenterY, relatedBy: .Equal, toItem: heroImageView, attribute: .CenterY, multiplier: 1, constant: 0)
    
    heroImageView.addConstraint(xConstraint)
    heroImageView.addConstraint(yConstraint)
    

    但是我无法将约束添加到我不认为的CALayer中,尝试时出现错误:

    由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'* + [NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]:约束项必须分别是UIView或NSLayoutGuide的实例。'* *

    看来问题可能是约束,但是如果我不能将约束添加到CALayer ...

    该代码没有帮助...

    不知道从这里去哪里,任何建议将不胜感激。

    最佳答案

    问题在于,当调用viewDidLoad时,布局尚未完成,因此您的测量是从 View Controller 的初始状态进行的,很有可能是从 Storyboard 的大小开始的(如果您使用的是这种情况)。

    布局完成且blurFilterMask的最终大小已知后,您需要调用heroImageView

    您可以通过覆盖viewDidLayoutSubviews来做到这一点,即...



    请阅读the docs,因为存在一些条件,但是在您的情况下确实可以,因此请您继续使用。

    class ViewController: UIViewController {
    
        @IBOutlet var heroImageView: UIImageView!
    
        var blurFilterMask:BlurFilterMask! = nil
    
        func resetMaskOverlay(){
    
            if blurFilterMask == nil {
    
                blurFilterMask = BlurFilterMask()
    
                blurFilterMask.diameter = 120
    
                heroImageView.layer.addSublayer(blurFilterMask)
    
            }
    
            blurFilterMask.frame = heroImageView.bounds
            blurFilterMask.origin = heroImageView.center
    
        }
    
    
        override func viewDidLayoutSubviews() {
            resetMaskOverlay()
        }
    
    }
    

    我假设这行是BlurFilterMask
        CGContextTranslateCTM(ctx, 0.0, yDiff)*/
    

    应该被注释掉,因为离开并没有太大意义。
    class BlurFilterMask : CALayer {
    
        let GRADIENT_WIDTH : CGFloat = 50.0
    
         var origin : CGPoint = CGPointZero {
            didSet {
                setNeedsDisplay()
            }
        }
        var diameter : CGFloat = 50.0 {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override func drawInContext(ctx: CGContext) {
            CGContextSaveGState(ctx)
    
            let clearRegionRadius : CGFloat  = self.diameter * 0.5
            let blurRegionRadius : CGFloat  = clearRegionRadius + GRADIENT_WIDTH
    
            let baseColorSpace = CGColorSpaceCreateDeviceRGB();
            let colours : [CGFloat] = [0.0, 0.0, 0.0, 0.0,     // Clear region
                0.0, 0.0, 0.0, 0.6] // blur region color
            let colourLocations : [CGFloat] = [0.0, 0.0]
            let gradient = CGGradientCreateWithColorComponents (baseColorSpace, colours, colourLocations, 2)
    
    
            CGContextDrawRadialGradient(ctx, gradient, self.origin, clearRegionRadius, self.origin, blurRegionRadius, .DrawsAfterEndLocation);
    
        }
    
     }
    

    ios - 添加以UIImageView为中心的CALayer子层-LMLPHP ios - 添加以UIImageView为中心的CALayer子层-LMLPHP

    10-08 15:43