添加以UIImageView为中心的CALayer子图层

时间:2016-02-15 02:53:19

标签: ios iphone xcode swift uiimageview

  • Xcode 7.2
  • Swift 2

我试图用我称之为“BlurFilterMask”的图像覆盖图像。它是我用Swift Code动态添加的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)
  • print(CGRectGetWidth(heroImageView.bounds))= 600.0
  • print(CGRectGetHeight(heroImageView.bounds))//135.0

但我的BlurFilterMask的中心总是不同的,取决于设备模拟器,它永远不会在UIImageView的中心启动,例如在iPhone 5中:

enter image description here

这是iPhone 6:

enter image description here

我想也许我需要在我的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添加约束......

该代码没有帮助......

不确定从何处开始,我们非常感谢任何建议。

1 个答案:

答案 0 :(得分:4)

问题在于,当viewDidLoad被调用时,布局还没有完成,所以你的测量是从视图控制器的初始状态获取的,很可能是故事板大小,如果这就是你正在使用的。

布局完成后,您需要致电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);

    }

 }

test1-5s test1-6s+