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

Bri*_*den 6 iphone xcode uiimageview ios swift

  • Xcode 7.2
  • 斯威夫特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);

    }

}
Run Code Online (Sandbox Code Playgroud)

在我的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()
    }
Run Code Online (Sandbox Code Playgroud)

无论我运行什么模拟器,无论是iPhone 5还是iPhone 6或iPad 2,例如,我总是得到相同的中心,宽度和高度:

  • print(heroImageView.center)=(300.0,67.5)
  • print(CGRectGetWidth(heroImageView.bounds))= 600.0
  • print(CGRectGetHeight(heroImageView.bounds))// 133.0

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

在此输入图像描述

这是iPhone 6:

在此输入图像描述

我想也许我需要在我的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)
Run Code Online (Sandbox Code Playgroud)

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

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

似乎问题可能是约束,但如果我不能向CALayer添加约束......

那段代码没有帮助......

不知道从哪里开始,任何建议将不胜感激.

War*_*ton 4

问题是,当viewDidLoad调用时,布局尚未完成,因此您的测量是从视图控制器的初始状态进行的,很可能是从故事板大小(如果您正在使用的话)进行的。

您需要blurFilterMask在布局完成并且heroImageView知道最终尺寸后调用。

您可以通过重写来做到这一点viewDidLayoutSubviews...

调用以通知视图控制器其视图刚刚布置了其子视图。

阅读文档,因为有一些条件,但在你的情况下,这确实有效,让你留下这个..

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()
    }

}
Run Code Online (Sandbox Code Playgroud)

我假设这条线在BlurFilterMask

    CGContextTranslateCTM(ctx, 0.0, yDiff)*/
Run Code Online (Sandbox Code Playgroud)

本来应该被注释掉,因为离开没有多大意义......

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);

    }

 }
Run Code Online (Sandbox Code Playgroud)

测试1-5秒 测试1-6s+