如何根据背景颜色自动更改视图的透明颜色

Posted

技术标签:

【中文标题】如何根据背景颜色自动更改视图的透明颜色【英文标题】:How to automatically change transparent color of a view based on the color of it’s background 【发布时间】:2020-06-24 11:28:16 【问题描述】:

我想在 uiimageview 上显示一个半透明的文本字段。我不能为文本字段选择静态颜色,因为有些图像很亮,而另一些图像很暗。我想根据其背后的颜色自动调整文本字段颜色。有没有简单的解决方案?

更新: 我想要达到的效果是: 如果 UIImage 在应该放置我的文本字段的位置很暗,请将文本字段背景颜色设置为白色,不透明度为 0.5。 如果 UIImage 在应该放置我的文本字段的位置很亮,请将文本字段背景颜色设置为黑色,不透明度为 0.5。

所以我想以某种方式计算要放置文本字段的 uiimageview 的平均颜色,然后检查它是浅色还是深色。我不知道,如何获取我的 uiimageview 特定部分的屏幕截图并获得它的平均颜色。我希望它被优化。我想使用 UIGraphicsImageRenderer 不是一个好的选择,这就是我问这个问题的原因。我知道如何使用 UIGraphicsImageRenderer 来做到这一点,但我认为我的方式还不够好。

【问题讨论】:

应该有一个选项来降低不透明度,这会给你一个半透明的效果。 ***.com/questions/46575839/… 亲爱的,没有什么是自动的。您必须更改颜色代码,然后进行相应更改。我建议你,如果你的 textfeidsl 是白色的,给文本字段黑色的阴影,反之亦然。 @Deitsch 谢谢你的回答。不幸的是,这不是我需要的。 @Ajjjjjjjj 这不是我要求的。我需要知道我的文本字段后面的 UIImage 是黑色还是白色。我还不知道。 【参考方案1】:

图像的“亮度”并不是一件简单的事情。您可能会也可能不会觉得这合适。

如果您搜索 determine brightness of an image,您会发现大量关于它的文档 - 可能比您想要的要多。

计算像素“亮度”的一种常用方法是使用以下各项之和:

red component   * 0.299
green component * 0.587
blue component  * 0.114

这是因为我们在不同的“亮度”级别上感知到不同的颜色。

因此,您需要遍历图像区域中要放置标签(或文本字段)的每个像素,获取平均亮度,然后确定什么是“暗”,什么是“亮”。

例如,使用这个背景图片:

我生成了一个 5 x 8 的标签网格,循环获取每个标签框架下 rect 中图像的“亮度”,然后根据亮度计算设置背景和文本颜色(值范围从 0 到255,所以我用 = 127 是亮的):

这是我使用的代码:

extension CGImage 
    var brightness: Double 
        get 
            // common formula to get "average brightness"
            let bytesPerPixel = self.bitsPerPixel / self.bitsPerComponent
            let imageData = self.dataProvider?.data
            let ptr = CFDataGetBytePtr(imageData)
            var x = 0
            var p = 0
            var result: Double = 0
            for _ in 0..<self.height 
                for _ in 0..<self.width 
                    let r = ptr![p+0]
                    let g = ptr![p+1]
                    let b = ptr![p+2]
                    result += (0.299 * Double(r) + 0.587 * Double(g) + 0.114 * Double(b))
                    p += bytesPerPixel
                    x += 1
                
            
            let bright = result / Double (x)
            return bright
        
    

extension UIImage 
    // get the "brightness" of self (entire image)
    var brightness: Double 
        get 
            return (self.cgImage?.brightness)!
        
    

    // get the "brightness" in a sub-rect of self
    func brightnessIn(_ rect: CGRect) -> Double 
        guard let cgImage = self.cgImage else  return 0.0 
        guard let croppedCGImage = cgImage.cropping(to: rect) else  return 0.0 
        return croppedCGImage.brightness
    


class ImageBrightnessViewController: UIViewController 
    
    let imgView: UIImageView = 
        let v = UIImageView()
        v.contentMode = .center
        v.backgroundColor = .green
        v.clipsToBounds = true
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    ()
    
    var labels: [UILabel] = []
    
    override func viewDidLoad() 
        super.viewDidLoad()

        // load an image
        guard let img = UIImage(named: "bkg640x360") else  return 

        imgView.image = img

        let w = img.size.width
        let h = img.size.height
        
        // set image view's width and height equal to img width and height
        view.addSubview(imgView)
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            imgView.widthAnchor.constraint(equalToConstant: w),
            imgView.heightAnchor.constraint(equalToConstant: h),
            imgView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            imgView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
        ])

        // use stack views to create a 5 x 8 grid of labels
        let outerStackView: UIStackView = 
            let v = UIStackView()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.axis = .horizontal
            v.spacing = 32
            v.distribution = .fillEqually
            return v
        ()

        for _ in 1...5 
            let vStack = UIStackView()
            vStack.axis = .vertical
            vStack.spacing = 12
            vStack.distribution = .fillEqually
            for _ in 1...8 
                let label = UILabel()
                label.textAlignment = .center
                vStack.addArrangedSubview(label)
                labels.append(label)
            
            outerStackView.addArrangedSubview(vStack)
        
        
        let padding: CGFloat = 12.0

        imgView.addSubview(outerStackView)
        NSLayoutConstraint.activate([
            outerStackView.topAnchor.constraint(equalTo: imgView.topAnchor, constant: padding),
            outerStackView.leadingAnchor.constraint(equalTo: imgView.leadingAnchor, constant: padding),
            outerStackView.trailingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: -padding),
            outerStackView.bottomAnchor.constraint(equalTo: imgView.bottomAnchor, constant: -padding),
        ])
        
    
    
    override func viewDidAppear(_ animated: Bool) 
        super.viewDidAppear(animated)
        guard let img = imgView.image else 
            return
        
        labels.forEach  v in
            if let sv = v.superview 
                // convert label frame to imgView coordinate space
                let rect = sv.convert(v.frame, to: imgView)
                // get the "brightness" of that rect from the image
                //  it will be in the range of 0 - 255
                let d = img.brightnessIn(rect)
                // set the text of the label to that value
                v.text = String(format: "%.2f", d)
                // just using 50% here... adjust as desired
                if d > 127.0 
                    // if brightness is than 50%
                    //  black translucent background with white text
                    v.backgroundColor = UIColor.black.withAlphaComponent(0.5)
                    v.textColor = .white
                 else 
                    // if brightness is greater than or equal to 50%
                    //  white translucent background with black text
                    v.backgroundColor = UIColor.white.withAlphaComponent(0.5)
                    v.textColor = .black
                
            
        
    

如您所见,在获取照片某个区域的平均值时,您通常不会对结果完全满意。这就是为什么看到一个或另一个更为常见的原因,具有对比顺序以及框架周围的阴影或发光。

【讨论】:

以上是关于如何根据背景颜色自动更改视图的透明颜色的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React Native 中设置透明视图的背景颜色

更改模态视图的背景颜色

如何根据Angularjs中的背景颜色自动更改文本颜色? [复制]

CSS中背景颜色透明度如何设置?

SwiftUI 如何根据获取的数据更改视图的背景颜色?

android studio中的任何视图都会根据设备默认主题更改背景颜色