简体   繁体   English

添加以UIImageView为中心的CALayer子层

[英]Add a CALayer sublayer centered over UIImageView

  • Xcode 7.2 Xcode 7.2
  • Swift 2 迅捷2

I am trying to overlay an Image with what I am calling a "BlurFilterMask". 我正在尝试用所谓的“ BlurFilterMask”覆盖图像。 It is a CALayer that I dynamically add with Swift Code, here is the 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);

    }

}

In my UIViewController.viewDidLoad() I call addMaskOverlay() and here is the implementation: 在我的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()
    }

No matter what Simulator I run in, be it iPhone 5 or iPhone 6 or iPad 2, for examples, I always get the same center, width and height: 例如,无论我运行的是什么模拟器,无论是iPhone 5,iPhone 6还是iPad 2,我总会得到相同的中心,宽度和高度:

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

But the center of my BlurFilterMask is always somewhere different, depending on the device simulator and it never starts in the center of UIImageView, example in iPhone 5: 但是我的BlurFilterMask的中心总是有所不同,具体取决于设备模拟器,并且它永远不会从UIImageView的中心开始,例如iPhone 5:

在此处输入图片说明

And here is iPhone 6: 这是iPhone 6:

在此处输入图片说明

I thought maybe I need vertically centering and horizontally centering constraints on my CALayer BlurFilterMask so I tried adding constraints: 我以为我可能需要在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)

But I cannot add Constraints to a CALayer I do not think, I get an error when I try: 但是我无法将约束添加到我不认为的CALayer中,尝试时出现错误:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]: Constraint items must each be an instance of UIView, or NSLayoutGuide.'** 由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'* + [NSLayoutConstraint ConstrainintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]:约束项必须分别是UIView或NSLayoutGuide的实例。'**

It seems like the issue might be constraints but if I cannot add constraints to a CALayer... 看来问题可能是约束,但是如果我无法将约束添加到CALayer ...

That code didn't help... 该代码没有帮助...

Not sure where to go from here, any suggestions would be much appreciated. 不知道从这里去哪里,任何建议将不胜感激。

The issue is that when viewDidLoad is called the layout has not been done yet so your measurements are being taken from the initial state of the view controller , most likely from the storyboard size if thats what you are using. 问题在于,当调用viewDidLoad时,布局尚未完成,因此您的测量是从视图控制器的初始状态开始进行的,很有可能是从情节提要的大小来进行的(如果您使用的是此情况)。

You need to call blurFilterMask once layout has completed and the final size of heroImageView is known. 一旦布局完成并且heroImageView的最终大小已知,则需要调用blurFilterMask

You can do this by overriding viewDidLayoutSubviews which is ... 您可以通过覆盖viewDidLayoutSubviews来做到这一点,即...

Called to notify the view controller that its view has just laid out its subviews. 调用以通知视图控制器其视图刚刚布置了其子视图。

Read the docs as there are some conditions but in your case this does work leaving you with this.. 请阅读文档,因为存在一些条件,但就您的情况而言,确实可以,因此请您自行设置。

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

}

I assumed this line in BlurFilterMask 我在BlurFilterMask假定了这一行

    CGContextTranslateCTM(ctx, 0.0, yDiff)*/

Was meant to be commented out as it didn't make much sense leaving... 应该被注释掉,因为离开并没有太大意义。

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

    }

 }

测试1-5 测试1-6

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM