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

  • Xcode 7.2
  • Swift 2

我正在试图用我称之为“BlurFilterMask”的图片覆盖图片。 这是一个CALayer,我dynamic地添加了Swift Code,这里是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() } 

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

  • print(heroImageView.center)=(300.0,67.5)
  • 打印(CGRectGetWidth(heroImageView.bounds))= 600.0
  • 打印(CGRectGetHeight(heroImageView.bounds))//135.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) 

但我不能将约束添加到CALayer我不认为,当我尝试时出现错误:

终止应用程序由于未捕获的exception'NSInvalidArgumentException',原因:'* + [NSLayoutConstraint constraintWithItem:属性:relatedBy:toItem:属性:乘数:常量:]:约束条目必须每个都是UIView或NSLayoutGuide的实例。

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

该代码没有帮助…

不知道从哪里走,任何build议将不胜感激。

问题是,当调用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() } } 

我在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 +