在 tableViewCell 中的 UIView 中放置渐变色

Place gradient color inside UIView in tableViewCell

我在堆栈视图中添加了两个视图。我的 tableViewCell 中有那个堆栈视图。现在我的 stackView 被放置在具有宽度和高度的内容视图的中心。我想在我的 stackView 内的视图中应用渐变颜色。

请看下面的视图 在本例中,我为视图提供了我不想要的红色和绿色背景色。我想将四种颜色的渐变应用于此视图。 enter image description here

下面是我在Swift写的一个简单的进度条代码:

import Foundation
import Cocoa

public class GradientProgressView : NSView
{
    // MARK: - Fields
    private let bgLayer = CAShapeLayer()
    private var progressLayer = CAShapeLayer()
    private var gradientLayer = CAGradientLayer()
    private var blockLayer = CAShapeLayer()
    private var mValue: CGFloat = 0.0
    
    // MARK: - Properties
    public var colors: [NSColor] = [NSColor.systemGreen, NSColor.systemYellow, NSColor.sytemRed]
    
    public var value: CGFloat
    {
        set
        {
            self.mValue = newValue
            
            if self.mValue > 1.0
            {
                self.mValue = 1.0
            }
            if self.mValue < 0.0 || self.mValue.isNaN || self.mValue.isInfinite
            {
                self.mValue = 0.0
            }
            
            self.progressLayer.strokeEnd = self.mValue
        }
        get
        {
            return self.mValue
        }
    }
    
    // MARK: - Overrides
    public override func layout()
    {
        super.layout()
        
        self.initialize()
    }
    
    // MARK: - Helper
    fileprivate func initialize()
    {
        self.wantsLayer = true
        
        self.layer?.masksToBounds = true // Optional
        self.layer?.cornerRadius = self.bounds.height / 2.0 // Optional
        
        self.bgLayer.removeFromSuperlayer()
        self.bgLayer.contentsScale = NSScreen.scale
        self.bgLayer.fillColor = NSColor.separatorColor.cgColor
        self.bgLayer.path = NSBezierPath(rect: self.bounds).cgPath
        self.layer?.addSublayer(self.bgLayer)
        
        self.blockLayer.removeAllAnimations()
        self.blockLayer.removeFromSuperlayer()
        
        let path = NSBezierPath()
        path.move(to: CGPoint(x: self.bounds.height / 2.0, y: self.bounds.height / 2.0))
        path.line(to: CGPoint(x: self.bounds.width - self.bounds.height / 2.0, y: self.bounds.height / 2.0))
        
        self.progressLayer.path = path.cgPath
        self.progressLayer.strokeColor = NSColor.black.cgColor
        self.progressLayer.fillColor = nil
        self.progressLayer.lineWidth = self.bounds.height
        self.progressLayer.lineCap = .round
        self.progressLayer.strokeStart = 0.0
        self.progressLayer.strokeEnd = 0.0
        self.progressLayer.contentsScale = NSScreen.scale
        
        self.gradientLayer.removeAllAnimations()
        self.gradientLayer.removeFromSuperlayer()
        self.gradientLayer.contentsScale = NSScreen.scale
        self.gradientLayer.colors = self.colors.map({ [=10=].cgColor })
        self.gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
        self.gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        self.gradientLayer.mask = self.progressLayer
        self.gradientLayer.frame = self.bounds
        self.gradientLayer.contentsScale = NSScreen.scale
        
        self.layer?.addSublayer(self.gradientLayer)
    }
}

这个进度条支持多种颜色。 只需将您的进度条逻辑替换为我在上面发布的逻辑(或添加进度条下方显示的三角形的逻辑)。

预览:

在 tableViewCell(collectionViewCell) 上创建 GradientLayer

1。在您的 tableViewCell

上创建 CAGradientLayer 实例
class MyCell: UITableViewCell {
    let gradientLayer = CAGradientLayer()
}

2。将图层框架设置为 layoutSublayers(of:)

的视图边界

如果将图层的框架设置在其他地方,框架会变得很奇怪。

class MyCell: UITableViewCell {
    let gradientLayer = CAGradientLayer()
    
    // Setting it from layoutSubViews also fine.
    override func layoutSublayers(of layer: CALayer) {
        super.layoutSublayers(of: self.layer)
        gradientLayer.frame = yourView.bounds
    }
}

3。在视图上添加 GradientLayer。

这是我添加渐变层的 UIView 扩展。

extension UIView {
    func addGradient(with layer: CAGradientLayer, gradientFrame: CGRect? = nil, colorSet: [UIColor],
                     locations: [Double], startEndPoints: (CGPoint, CGPoint)? = nil) {
        layer.frame = gradientFrame ?? self.bounds
        layer.frame.origin = .zero

        let layerColorSet = colorSet.map { [=12=].cgColor }
        let layerLocations = locations.map { [=12=] as NSNumber }

        layer.colors = layerColorSet
        layer.locations = layerLocations

        if let startEndPoints = startEndPoints {
            layer.startPoint = startEndPoints.0
            layer.endPoint = startEndPoints.1
        }

        self.layer.insertSublayer(layer, above: self.layer)
    }
}
* 选项 1 - 从 layoutSublayers(of:) 添加
class MyCell: UITableViewCell {
    let gradientLayer = CAGradientLayer()
    
    override func layoutSublayers(of layer: CALayer) {
        super.layoutSublayers(of: self.layer)
        gradientLayer.frame = yourView.bounds
        
        let colorSet = [UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1.0),
                        UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0)]
        let location = [0.2, 1.0]
        
        yourView.addGradient(with: gradientLayer, colorSet: colorSet, locations: location)
    }
}
* 选项 2 - 从 cellForRowAt 添加

例如,如果我们有 cellForRowAt 并且像这样,

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: "yourCellId", for: indexPath) as? MyCell {
      cell.configureCell(content: someItems[indexPath.row])
  }
  return UITableViewCell()
}

现在,我们可以处理来自 configureCell(content:) 的 gradientLayer。

class MyCell: UITableViewCell {
    let gradientLayer = CAGradientLayer()
    
    func configureCell(content: YourType) {
        let colorSet = [UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1.0),
                        UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1.0)]
        let location = [0.2, 1.0]
        yourView.addGradient(with: gradientLayer, colorSet: colorSet, locations: location)
    }
    
    override func layoutSublayers(of layer: CALayer) {
        super.layoutSublayers(of: self.layer)
        gradientLayer.frame = yourView.bounds
    }
}