UITableViewCell 背景渐变在第一次渲染时不起作用

Posted

技术标签:

【中文标题】UITableViewCell 背景渐变在第一次渲染时不起作用【英文标题】:UITableViewCell background gradient not working at first render 【发布时间】:2018-12-29 23:32:14 【问题描述】:

我有一个表格视图。我使用 xib 文件创建单元格。 我需要 1 个单元格(即当前用户)作为渐变背景,我创建了一个背景渐变层,但它不适合查看。在我下拉列表后,它可以工作。

你可以看到我的截图,这是我的代码

//In the table cell,
if data.userUniqueId != nil && userUIID != nil && data.userUniqueId! == userUIID! 
            let startColor = UIColor(red: 253/255.0, green: 162/255.0, blue: 75/255.0, alpha: 1)
            let endColor = UIColor(red:251/255.0, green:215/255.0, blue: 126/255.0, alpha:1)
            self.setGradient(colors: [startColor.cgColor, endColor.cgColor],angle: 90)
            self.layer.borderColor = UIColor.white.cgColor
            self.layer.borderWidth = 2
            number.textColor = UIColor.white

        

这是梯度法

 func setGradient(colors: [CGColor], angle: Float = 0) 
        let gradientLayerView: UIView = UIView(frame: CGRect(x:0, y: 0, width: bounds.width, height: bounds.height))
        let gradient: CAGradientLayer = CAGradientLayer()
        gradient.frame = gradientLayerView.bounds
        gradient.colors = colors

        let alpha: Float = angle / 360
        let startPointX = powf(
            sinf(2 * Float.pi * ((alpha + 0.75) / 2)),
            2
        )
        let startPointY = powf(
            sinf(2 * Float.pi * ((alpha + 0) / 2)),
            2
        )
        let endPointX = powf(
            sinf(2 * Float.pi * ((alpha + 0.25) / 2)),
            2
        )
        let endPointY = powf(
            sinf(2 * Float.pi * ((alpha + 0.5) / 2)),
            2
        )

        gradient.endPoint = CGPoint(x: CGFloat(endPointX),y: CGFloat(endPointY))
        gradient.startPoint = CGPoint(x: CGFloat(startPointX), y: CGFloat(startPointY))

        gradientLayerView.layer.insertSublayer(gradient, at: 0)
        layer.insertSublayer(gradientLayerView.layer, at: 0)
    

还有如何从图层中移除渐变以便下次使用单元格?

编辑: 表格查看代码

extension RecordsViewController : UITableViewDataSource 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return values.count
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        if let cell = tableView.dequeueReusableCell(withIdentifier: "ScoreBoardCell", for: indexPath) as? ScoreBoardCell 
            let score = self.values[indexPath.row]
            cell.setData(indexPath.row, score)
            cell.selectionStyle = .none
            return cell
        
        return UITableViewCell()
    

【问题讨论】:

请显示cellForRowAt整体 【参考方案1】:

问题出在这一行:

gradient.frame = gradientLayerView.bounds

这段代码在cellForRowAt运行时,你的gradientLayerView还没有完全布局,所以它的bounds还不知道。因此,您正在为您的gradient 设置一个frame,这在布局发生后将不适合其视图。

认为您可以通过将调用移动到cell.setDatatableView(_:willDisplay:forRowAt:) 来解决问题,此时应该知道单元格大小。

还有如何从图层中移除渐变以便下次使用单元格?

好吧,这里的问题是你的情况别无选择:

if data.userUniqueId != nil && userUIID != nil && data.userUniqueId! == userUIID!

问题是:如果不是怎么办?在这种情况下,如果已添加渐变层,则需要将其移除。你没有为这种情况提供任何逻辑。 — 你也需要小心,因为如果已经添加了渐变层并且你的逻辑现在导致你添加另一个渐变层怎么办?基本上,您的整个方法没有考虑到关于表格视图单元格的最基本事实,即它们被重用。

【讨论】:

将 layoutSubView 覆盖到 UITableCellView 是否有效? 它可能,是的。试一试。 它成功了,谢谢,我有一个 else 声明,但我没有在这里写。我找不到如何从 CALayer 中删除渐变 您不会“从 CALayer 中删除渐变”。您删除渐变层本身。这就是removeFromSuperlayer 的用途,是吗?【参考方案2】:

[Xcode 12 Swift 5.2]

找了几个小时后,我没有任何工作。在layoutSubviews() 中更改渐变层的边界或在willDisplayCell() 中设置渐变层。

所以我创建了一个渐变层并创建了一个UIImage 并将该图像添加为背景。在这里就像魅力一样工作是一个甜蜜而简单的扩展,用于将 Gradient 层转换为 UIImage

func getImageFrom(gradientLayer:CAGradientLayer) -> UIImage? 
        var gradientImage:UIImage?
        UIGraphicsBeginImageContext(gradientLayer.frame.size)
        if let context = UIGraphicsGetCurrentContext() 
            gradientLayer.render(in: context)
            gradientImage = UIGraphicsGetImageFromCurrentImageContext()?.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch)
        
        UIGraphicsEndImageContext()
        return gradientImage
    

制作CAGradientLayer的代码:

 let gradientLayer = CAGradientLayer()
gradientLayer.colors = [
            UIColor.init().Hex(hexString: "#EB0089").cgColor,
            UIColor.init().Hex(hexString: "#FD2E59").cgColor
        ]
        
        gradientLayer.cornerRadius = self.layer.cornerRadius
        
       
        gradientLayer.startPoint = CGPoint(x: 0, y: 1)
        gradientLayer.endPoint = CGPoint(x: 0, y: 0)
        gradientLayer.frame = Button1.bounds

let GradientImage = UIImage().getImageFrom(gradientLayer: gradientLayer)

GradientImage 设置在您想要的任何位置。

【讨论】:

【参考方案3】:

你需要在里面调用这个

var once  = true

override func layoutSubviews() 
  super.layoutSubviews()
  if once  
        let startColor = UIColor(red: 253/255.0, green: 162/255.0, blue: 75/255.0, alpha: 1)
        let endColor = UIColor(red:251/255.0, green:215/255.0, blue: 126/255.0, alpha:1)
        self.setGradient(colors: [startColor.cgColor, endColor.cgColor],angle: 90)
        once = false 
      

单元格边界正确呈现的位置,何时要删除

cell.contentView.subviews  
  if $0.tag == 200 
    $0.removeFromSuperview()
  
 

并给它一个标签

 let gradientLayerView: UIView = UIView(frame: CGRect(x:0, y: 0, width: bounds.width, height: bounds.height))
 gradientLayerView.tag = 200

当您向单元格添加任何内容时,请不要将其添加到 contentView

contentView.addSubview(gradientLayerView)

【讨论】:

以上是关于UITableViewCell 背景渐变在第一次渲染时不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableViewCell 中使用渐变背景 [重复]

在 UITableViewCell 中使用渐变作为背景 [重复]

如何在情节提要中向原型 UITableViewCell 添加渐变背景颜色?

渐变没有填充 UITableViewCell

UITableViewCell 中的渐变出现在内容上

滚动后 UITableViewCell 内的 UIView 中的渐变发生了变化