给标签添加模糊视图?

10
我如何在标签上添加模糊视图?标签位于UIImage的前面,我希望标签的背景被模糊处理,以便用户可以更好地阅读文本。我在标签边界内获得了模糊效果,但文本本身消失了(也许也变得模糊了,我不知道为什么)。我还尝试以编程方式添加标签,但无法使其正常工作。感谢任何形式的帮助!
let blur = UIBlurEffect(style: .Light)
    let blurView = UIVisualEffectView(effect: blur)

    blurView.frame = findATeamLabel.bounds
    findATeamLabel.addSubview(blurView)

1
你正在对标签添加模糊视图。你应该在标签后面添加它。 - Teja Nandamuri
那正是我所想的,但怎么做呢? :D - beginner_T
将模糊视图添加到标签后面的图层中...查看如何在图层后面添加图层。 - Teja Nandamuri
[self.view.layer insertSublayer:visualeffectView.layer below:label.layer]我认为你可以将这段代码转换为 Swift。 - Teja Nandamuri
不幸的是,它不起作用:/ - beginner_T
显示剩余2条评论
5个回答

8
你可以制作自己的模糊标签,以实现文本的模糊/非模糊。通过CoreImage模糊滤镜,你可以将标签的文本进行模糊处理,并在标签上方显示该图像。
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
    }
}

提示:请根据您的要求改进此组件(例如,如果已经模糊,请避免再次模糊,或者如果文本更改,则可以删除当前的模糊并重新应用模糊)。

另外需要考虑的是,将模糊应用于某些内容会导致其内容溢出,因此要么将clipsToBounds=false应用于BlurredLabel,要么找到其他实现视觉效果的方法,以避免模糊图像看起来不在与之前未模糊的标签文本相同的位置。

要使用它,您可以简单地创建一个BlurredLabel

let blurredLabel = BlurredLabel()
blurredLabel.text = "56.00 €"

在点击某个按钮时,您可以通过blurredLabel.blur()进行模糊操作,并通过blurredLabel.unblur()取消模糊。

使用blur()方法并将模糊半径设为2.5,可以获得以下输出:

要了解更多高斯模糊的信息,可以查阅维基百科上的相关文章:https://en.wikipedia.org/wiki/Gaussian_blur


1
如果在视图布局完成后调用blur()函数,那么这个方法非常好用。然而,在我的情况下,标签位于UITableViewCells中,因此当标签布局完成时,我无法调用blur()函数。有什么想法吗? - Ludovico Verniani
1
初始化后模糊标签会导致“在UIGraphicsGetCurrentContext()!中意外发现了nil值”的错误。 - XY Li
如何在初始化后使标签模糊? - XY Li
1
这个问题在这里得到了回答,https://dev59.com/rL3pa4cB1Zd3GeqPgo81。 - XY Li

2

Swift 5 - 将模糊效果作为UIView扩展

extension UIView {
    
    struct BlurableKey {
        static var blurable = "blurable"
    }
    
    func blur(radius: CGFloat) {
        guard superview != nil else { return }
        
        UIGraphicsBeginImageContextWithOptions(CGSize(width: frame.width, height: frame.height), false, 1)
        layer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        guard
            let blur = CIFilter(name: "CIGaussianBlur"),
            let image = image
        else {
            return
        }
  
        blur.setValue(CIImage(image: image), forKey: kCIInputImageKey)
        blur.setValue(radius, forKey: kCIInputRadiusKey)
        
        let ciContext  = CIContext(options: nil)
        let boundingRect = CGRect(
            x:0,
            y: 0,
            width: frame.width,
            height: frame.height
        )
        
        guard
            let result = blur.value(forKey: kCIOutputImageKey) as? CIImage,
            let cgImage = ciContext.createCGImage(result, from: boundingRect)
        else {
            return
        }
                
        let blurOverlay = UIImageView()
        blurOverlay.frame = boundingRect
        blurOverlay.image = UIImage(cgImage: cgImage)
        blurOverlay.contentMode = .left
        
        addSubview(blurOverlay)
     
        objc_setAssociatedObject(
            self,
            &BlurableKey.blurable,
            blurOverlay,
            objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN
        )
    }
    
    func unBlur() {
        guard
            let blurOverlay = objc_getAssociatedObject(self, &BlurableKey.blurable) as? UIImageView
        else {
            return
        }
        
        blurOverlay.removeFromSuperview()
        
        objc_setAssociatedObject(
            self,
            &BlurableKey.blurable,
            nil,
            objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN
        )
    }
    
    var isBlurred: Bool {
        return objc_getAssociatedObject(self, &BlurableKey.blurable) is UIImageView
    }
}

2
你可以尝试将它发送到标签的视图层次结构的后面。尝试使用以下代码: findATeamLabel.sendSubviewToBack(blurView)

2
我也尝试过那个,但是仍然一切都模糊不清,没有文字。 - beginner_T
@beginner_T 我也遇到了同样的问题,后来我找到了这篇文章,并提供了一个使用自定义UILabel可以模糊其文本的答案,请在此处查看:https://dev59.com/2FoV5IYBdhLWcg3wc-jo#62224908 - denis_lor

1

我通过在标签后面添加一个视图(标签不在该视图内,而是在其前面)来使其工作。然后我将模糊效果添加到视图上... 我仍然认为应该有一种更简单的方法。


0

对我来说,这些答案都不起作用。被接受的答案不能处理不同颜色背景或标签颜色不同于黑色的情况。根据评论,它跳到了另一个问题,但是答案使得模糊移动到右侧很多。因此,在阅读一些内容后,我调整了结果图像上的CGRect。

   class BlurredLabel: UILabel {
    
    var isBlurring = false {
        didSet {
            setNeedsDisplay()
        }
    }
    
    var blurRadius: Double = 8 {
        didSet {
            blurFilter?.setValue(blurRadius, forKey: kCIInputRadiusKey)
        }
    }
    
    lazy var blurFilter: CIFilter? = {
        let blurFilter = CIFilter(name: "CIGaussianBlur")
        blurFilter?.setDefaults()
        blurFilter?.setValue(blurRadius, forKey: kCIInputRadiusKey)
        return blurFilter
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        layer.isOpaque = false
        layer.needsDisplayOnBoundsChange = true
        layer.contentsScale = UIScreen.main.scale
        layer.contentsGravity = .center
        isOpaque = false
        isUserInteractionEnabled = false
        contentMode = .redraw
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    override func display(_ layer: CALayer) {
        let bounds = layer.bounds
        guard !bounds.isEmpty && bounds.size.width < CGFloat(UINT16_MAX) else {
            layer.contents = nil
            return
        }
        UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.isOpaque, layer.contentsScale)
        if let ctx = UIGraphicsGetCurrentContext() {
            self.layer.draw(in: ctx)
            
            var image = UIGraphicsGetImageFromCurrentImageContext()?.cgImage
            if isBlurring {
                blurFilter?.setValue(CIImage(cgImage: image!), forKey: kCIInputImageKey)
                let ciContext = CIContext(cgContext: ctx, options: nil)
                if let blurOutputImage = blurFilter?.outputImage {
                    let boundingRect = CGRect(
                                x:0,
                                y: blurOutputImage.extent.minY,
                                width: blurOutputImage.extent.width,
                                height: blurOutputImage.extent.height
                            )
                    
                    
                    image = ciContext.createCGImage(blurOutputImage, from: boundingRect)
                }
                 
            }
            layer.contents = image
            
        }
        UIGraphicsEndImageContext()
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接