【问题标题】:CAGradientLayer not resizing correctly when UITableViewCell is shown显示 UITableViewCell 时 CAGradientLayer 无法正确调整大小
【发布时间】:2020-03-14 06:44:36
【问题描述】:

我正在开发一个应用程序,它在 tableViewCell 中显示头像图片和一些个人资料信息。相同的头像图片设置为单元格背景,然后我在它上面有另一个带有渐变的UIView,它是使用CAGradientLayer创建的。

问题是,当我的单元格显示时,渐变没有正确的帧大小(应该是单元格的大小),而是在右侧留下一个空白区域。当我滚动 tableView 时,渐变会正确调整大小。

这是我创建渐变的方法:

func awakeFromNib() {
    let startColor = UIColor.gradientOverlay.cgColor //Defined elsewhere
    let endColor = UIColor.black.cgColor

    gradientLayer.frame = gradientView.frame
    gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
    gradientLayer.endPoint = CGPoint(x: 0.5, y: 1)
    gradientLayer.colors = [startColor, endColor]
    self.gradientView.layer.addSublayer(gradientLayer)
}

另外,我已经像这样覆盖了layoutSubviews 方法:

override func layoutSubviews() {
    super.layoutSubviews()

    gradientLayer.frame = gradientView.frame
    self.layoutIfNeeded()
}

呈现视图时屏幕如下所示(我已删除敏感信息):

请注意,在右侧的标签之后,颜色会发生变化。最后一个颜色列只是模拟器屏幕的边框。

你们知道如何解决这个问题吗?

编辑:更正标题上的错字。

【问题讨论】:

  • 不确定它是否有帮助,但可能值得尝试在layoutSubviews() 末尾调用self.layer.layoutIfNeeded()self.layer.layoutSublayers() 以使图层几何形状适应任何修改后的视图几何形状。

标签: ios swift uitableview core-animation cagradientlayer


【解决方案1】:

我找到了解决方法。由于问题在于层的宽度,我使用UIScreen.main.bounds.width 初始化了它的宽度。

【讨论】:

    【解决方案2】:

    渐变本身使用CAGradientLayer 女巫是CALayer 而不是UIView。所以视图布局不会影响它。

    自定义类

    你可以使用我写的这个类:

    class GradientView: UIView {
    
        var colors: [UIColor]? { didSet { syncColors() } }
    
        var direction: GradientDirection = .topToBottom {
            didSet {
                layer.startPoint = direction.startPoint
                layer.endPoint = direction.endPoint
            }
        }
    
        enum GradientDirection {
            case rightToLeft
            case leftToRight
            case bottomToTop
            case topToBottom
            case custom(startPoint: CGPoint,endPoint: CGPoint)
    
            var startPoint: CGPoint {
                switch self {
                case .rightToLeft: return CGPoint(x: 1, y: 0)
                case .leftToRight: return .zero
                case .bottomToTop: return CGPoint(x: 0, y: 1)
                case .topToBottom: return .zero
                case .custom(let startPoint, _): return startPoint
                }
            }
    
            var endPoint: CGPoint {
                switch self {
                case .rightToLeft: return .zero
                case .leftToRight: return CGPoint(x: 1, y: 0)
                case .bottomToTop: return .zero
                case .topToBottom: return CGPoint(x: 0, y: 1)
                case .custom(_, let endPoint): return endPoint
                }
            }
    
            static var interfaceDirection: GradientDirection {
                switch UIApplication.shared.userInterfaceLayoutDirection {
                case .leftToRight: return .leftToRight
                case .rightToLeft: return .rightToLeft
                }
            }
        }
    
        override class var layerClass: AnyClass { return CAGradientLayer.self }
    
        override var layer: CAGradientLayer { return super.layer as! CAGradientLayer }
    
        override func layoutSubviews() { syncColors() }
    
        private func syncColors() { layer.colors = colors?.map() { $0.cgColor } }
    }
    

    简化类

    借助这个简单的类:

    enum GradientDirection {
        case rightToLeft
        case leftToRight
        case bottomToTop
        case topToBottom
        case custom(startPoint: CGPoint,endPoint: CGPoint)
    
        var startPoint: CGPoint {
            switch self {
            case .rightToLeft: return CGPoint(x: 1, y: 0)
            case .leftToRight: return .zero
            case .bottomToTop: return CGPoint(x: 0, y: 1)
            case .topToBottom: return .zero
            case .custom(let startPoint, _): return startPoint
            }
        }
    
        var endPoint: CGPoint {
            switch self {
            case .rightToLeft: return .zero
            case .leftToRight: return CGPoint(x: 1, y: 0)
            case .bottomToTop: return .zero
            case .topToBottom: return CGPoint(x: 0, y: 1)
            case .custom(_, let endPoint): return endPoint
            }
        }
    
        static var interfaceDirection: GradientDirection {
            switch UIApplication.shared.userInterfaceLayoutDirection {
            case .leftToRight: return .leftToRight
            case .rightToLeft: return .rightToLeft
            }
        }
    }
    

    那么你就有了一个普通视图,它可以对来自超级视图的任何布局通知做出反应。

    用法

    只需添加子视图并将类设置为GradientView 并使用自动布局或您想要的任何其他布局进行布局。

    或使用代码:

        let gradientView: GradientView = {
            let gradientView = GradientView(frame: self.frame)
            gradientView.colors = [
                UIColor.black.withAlphaComponent(1),
                UIColor.black.withAlphaComponent(0)
            ]
            gradientView.direction = .bottomToTop
    
            return gradientView
        }()
    

    请注意,如果您希望它具有一定的透明度,则需要删除视图的原始backgroundColor

    【讨论】:

    • 这实际上非常有用,但我现在会尝试使用 CAGradientLayer。但是,如果我不能这样做,我会确保尝试您的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多