在动态大小的 UITableViewCell 上应用 CAGradientLayer

Posted

技术标签:

【中文标题】在动态大小的 UITableViewCell 上应用 CAGradientLayer【英文标题】:Applying CAGradientLayer on Dynamically Sized UITableViewCell 【发布时间】:2022-01-01 03:22:29 【问题描述】:

背景:我的应用程序允许用户选择渐变边框以应用于根据其中的内容动态调整大小的 UITableViewCells。我目前正在通过将 CAGradientLayer 子层插入单元格内的 UIView 来创建此边框。

问题:因为每个单元格的大小不同,我通过在我的自定义单元格类中覆盖 layoutIfNeeded 来调整 CAGradientLayer 的大小。这可行,但似乎不是最理想的,因为边框被一遍又一遍地重绘,并且随着单元格大小的调整而闪烁。

屏幕截图链接: https://drive.google.com/file/d/1SiuNozyUM7LCdYImZoGCWeoeBKu2Ulcw/view?usp=sharing

问题:我是否需要采用不同的方法来创建此边框?或者我错过了关于 UITableViewCell 生命周期的一些东西?我在 SO 上遇到过类似的问题,但似乎没有一个可以解决这个重绘问题。感谢您的帮助。

CAGradientLayer 扩展创建边框

extension CAGradientLayer 
    
    func createBorder(view: UIView, colors: [CGColor]) 
        self.frame =  CGRect(origin: CGPoint.zero, size: view.bounds.size)
        self.colors = colors
        
        let shape = CAShapeLayer()
        shape.lineWidth = 14
        shape.path = UIBezierPath(roundedRect: view.bounds, cornerRadius: 12).cgPath
        shape.strokeColor = UIColor.black.cgColor
        shape.fillColor = UIColor.clear.cgColor
        self.mask = shape
    

TableViewCell 类 - 插入 CAGradientLayer

override func awakeFromNib() 
   super.awakeFromNib()           
   reportCard.layer.insertSublayer(gradientLayer, at: 0)
   ...

TableViewCell 类 - 调整边框大小并应用用户选择的设计

override func layoutIfNeeded() 
        super.layoutIfNeeded()
            
        switch currentReport?.frameId 
        case "sj_0099_nc_frame_001":
            gradientLayer.createBorder(view: reportCard, colors: [App.BorderColors.lavender, App.BorderColors.white])
        case "sj_0099_nc_frame_002":
            gradientLayer.createBorder(view: reportCard, colors: [App.BorderColors.red, App.BorderColors.white])
        case "sj_0099_nc_frame_003":
            gradientLayer.createBorder(view: reportCard, colors: [App.BorderColors.yellow, App.BorderColors.white])
        default:
            gradientLayer.createBorder(view: reportCard, colors: [App.BorderColors.white, App.BorderColors.white])
        
 

【问题讨论】:

【参考方案1】:

原来我一直在找错地方。我原始帖子中的代码是功能性的,并且在 layoutIfNeeded() 或 setNeedsLayout() 中更新 gradientLayer 框架而不是 layoutSubviews() 可以准确地绘制 gradientLayer。根据 Apple 文档,不应直接调用 layoutSubviews()。

错误的根源不在我的自定义单元格中,而是在我的 tableViewController 中。我有一个无关的调用 reloadData()。

【讨论】:

【参考方案2】:

不要在 awakeFromNib() 内部使用这个

override func layoutSubviews() 

   super.layoutSubviews()
   
    reportCard.layer.insertSublayer(gradientLayer, at: 0)
    reportCard.clipsToBounds = true

【讨论】:

很遗憾,这并不能解决问题。 您能解释一下它的外观或您的确切问题是什么 当然。我刚刚更新了我的帖子,以包含指向它外观记录的链接。谢谢。 尝试在 layoutSubviews 和 var reportCards add didset with self.reportCards.layoutIfNeeded() 头撞墙几天后,我发现问题的根源不在自定义单元格类中,并将我的发现发布在上面。感谢您一路上的帮助!

以上是关于在动态大小的 UITableViewCell 上应用 CAGradientLayer的主要内容,如果未能解决你的问题,请参考以下文章

UITableViewCell 不使用 Swift 动态调整大小

在 UITableViewCell 中调整 UIImageView 的大小,动态使用 textlabel

在具有自动布局的 UITableViewCell 中动态调整大小的 UIWebView - 违反约束

如何根据 UITableView 滚动动态调整 UITableViewCell 的大小?

根据 UILabel 动态调整 uitableViewCell 大小(带段落间距)

UiTableViewCell 动态高度适用于 iphone 而不是 ipad 大小类