我正在尝试用所谓的“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,我总会得到相同的中心,宽度和高度:
但是我的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中,尝试时出现错误:
由于未捕获的异常'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);
}
}