【发布时间】:2021-01-19 21:24:26
【问题描述】:
我正在按照代码示例制作模糊的 UILabel,https://stackoverflow.com/a/62224908/2226315。
我的要求是在标签初始化后使标签模糊,而不是在运行时调用blur 方法。但是,当我在标签初始化后尝试调用blur 时,从UIGraphicsGetCurrentContext 返回的值是nil,因此出现“致命错误:在展开可选值时意外发现nil”
UIGraphicsBeginImageContext(bounds.size)
print("DEBUG: bounds.size", bounds.size)
self.layer.render(in: UIGraphicsGetCurrentContext()!) // <- return nil
var image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
print("DEBUG: image image", image)
我尝试在以下所有位置分别添加代码,现在可以获取上下文但是它不会产生预期的模糊效果。
override func layoutSubviews() {
super.layoutSubviews()
self.blur()
}
// OR
override func draw(_ rect: CGRect) {
super.draw(rect)
self.blur()
}
全码sn-p,
class BlurredLabel: UILabel {
func blur(_ blurRadius: Double = 2.5) {
let blurredImage = getBlurryImage(blurRadius)
let blurredImageView = UIImageView(image: blurredImage)
blurredImageView.translatesAutoresizingMaskIntoConstraints = false
blurredImageView.tag = 100
blurredImageView.contentMode = .center
blurredImageView.backgroundColor = .white
addSubview(blurredImageView)
NSLayoutConstraint.activate([
blurredImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
blurredImageView.centerYAnchor.constraint(equalTo: centerYAnchor)
])
}
func unblur() {
subviews.forEach { subview in
if subview.tag == 100 {
subview.removeFromSuperview()
}
}
}
private func getBlurryImage(_ blurRadius: Double = 2.5) -> UIImage? {
UIGraphicsBeginImageContext(bounds.size)
layer.render(in: UIGraphicsGetCurrentContext()!)
guard let image = UIGraphicsGetImageFromCurrentImageContext(),
let blurFilter = CIFilter(name: "CIGaussianBlur") else {
UIGraphicsEndImageContext()
return nil
}
UIGraphicsEndImageContext()
blurFilter.setDefaults()
blurFilter.setValue(CIImage(image: image), forKey: kCIInputImageKey)
blurFilter.setValue(blurRadius, forKey: kCIInputRadiusKey)
var convertedImage: UIImage?
let context = CIContext(options: nil)
if let blurOutputImage = blurFilter.outputImage,
let cgImage = context.createCGImage(blurOutputImage, from: blurOutputImage.extent) {
convertedImage = UIImage(cgImage: cgImage)
}
return convertedImage
}
}
参考
更新
基于“Eugene Dudnyk”答案的用法
definitionLabel = BlurredLabel()
definitionLabel.numberOfLines = 0
definitionLabel.lineBreakMode = .byWordWrapping
definitionLabel.textColor = UIColor(named: "text")
definitionLabel.text = "Lorem Ipsum is simply dummy text"
definitionLabel.clipsToBounds = false
definitionLabel.isBluring = true
【问题讨论】:
-
你检查过
CGRectIsEmpty(bounds) == false吗? -
一种更简单的方法可能是将 UIVisualEffectView 添加为标签的子视图,并在需要时将其隐藏。您可以将 UIBlurEffect 附加到 UIVisualEffectView 以获得所需的效果
-
@Pastre 我试图将标签放在 UIVisualEffectView 后面,但它看起来不如通过 CoreImage 创建的模糊效果。
-
@EugeneDudnyk 我刚刚检查了边界,标签初始化后它是空的。您能否与我分享一下获取上下文的正确位置?
-
如果边界是空的,你甚至不应该画任何东西。在这种情况下,Label 不会在屏幕上占据任何空间,稍后它将获得非空边界。只是在获得边界之前不要创建上下文。
标签: ios swift uikit core-image