根据单元格索引路径向 table 视图单元格元素添加渐变层

Adding a gradient layer to a table view cell element dependant on the cell index path

我很难将渐变图层作为背景添加到 table 视图单元格内的元素。渐变层取决于单元格索引路径。我有一个 enum 的颜色,它使用 indexPath 作为它的 rawValue。所需的输出很简单,例如 this

这是创建渐变图层的函数。我用这个tutorial来写函数。

func setGradientBackground(colorOne: UIColor, colorTwo: UIColor, name: String) {
    let gradient = CAGradientLayer()
    gradient.frame = bounds
    gradient.colors = [colorOne.cgColor, colorTwo.cgColor]
    gradient.locations = [0, 1]
    gradient.startPoint = CGPoint(x: 1, y: 1)
    gradient.endPoint = CGPoint(x: 0, y: 0)
    gradient.name = name
    layer.insertSublayer(gradient, at: 0)
}

要将渐变添加到 table 视图单元格中的元素,已经尝试了一些方法。目前我正在遍历可见单元格以添加图层。我试过从 viewWillLayoutSubviews 打电话。这是我唯一一次看到应用的渐变。

我发现了两个问题。该应用程序变得无法使用,因为我认为当视图上的某些内容发生变化时,此功能或多或少会被连续调用。并且图层绘制在单元格中的所有其他内容上。

func configTableCells() {
    guard let cells = self.tableView.visibleCells as? [GroupTableCell] else {return}
    for (i, cell) in cells.enumerated() {
        if shouldAddSubLayer(cell) {
            guard let colorOne = Colors(rawValue: i)?.classicColor,
                let colorTwo = Colors(rawValue: i)?.alternativeColor else {continue}
            cell.taskInfoCollectionView.setGradientBackground(colorOne: colorOne,
                                                              colorTwo: colorTwo,
                                                              name: cellLayerName)
        }
    }
}

我尝试在 cellForRowAtwillDisplay Cell 中添加图层,但这没有用。我相信这是因为单元格还没有 'exist' 所以添加一层没有区别。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: groupCellId, for: indexPath) as! GroupTableCell
    cell.groupNameLabel.text = "Group Name"
    cell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
    if shouldAddSubLayer(cell) {
        if let colorOne = Colors(rawValue: indexPath.row)?.classicColor,
            let colorTwo = Colors(rawValue: indexPath.row)?.alternativeColor {
        cell.taskInfoCollectionView.setGradientBackground(colorOne: colorOne,
                                                          colorTwo: colorTwo,
                                                          name: cellLayerName)
        }
    }
    return cell
} 

我还包含了这个函数,因为我阅读了另一个 Whosebug 问题,我应该检查单元格是否已经有层以避免连续添加它。 (我不能 link 这个问题,因为我现在找不到它)

func shouldAddSubLayer(_ cell: GroupTableCell) -> Bool {
    guard let sublayers = cell.layer.sublayers else {return true}
    return sublayers.filter({ [=14=].name == cellLayerName }).count == 0
}

欢迎就如何实现此工作提出任何建议,谢谢。

试试 VisualEffect

在您的 ViewDidLoad()

中添加以下代码
if (!UIAccessibilityIsReduceTransparencyEnabled()) {
tableView.backgroundColor = UIColor.clear
let blurEffect = UIBlurEffect(style: .light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
tableView.backgroundView = blurEffectView

//if inside a popover
if let popover = navigationController?.popoverPresentationController {
    popover.backgroundColor = UIColor.clear
}

//if you want translucent vibrant table view separator lines
tableView.separatorEffect = UIVibrancyEffect(blurEffect: blurEffect)}

对于可能觉得这很有用的任何人,请了解使其正常工作所需的更改..

使用 Ben 建议的 Visual Effect,我能够使它正常工作。我从未使用过 Visual Effects,所以不确定它究竟为何起作用。同样,我可能需要进行一些改进

在自定义 table 单元格 class 中,我添加了一个 UIVisualEffectView。在其内容视图中,我添加了我想要更改其背景的元素。

Add any subviews to the contentView property of the visual effect view. Do not add subviews directly to the visual effect view itself

lazy var visualEffectView: UIVisualEffectView = {
    let v = UIVisualEffectView()
    v.translatesAutoresizingMaskIntoConstraints = false
    v.contentView.addSubview(taskInfoCollectionView)
    NSLayoutConstraint.activate([
        taskInfoCollectionView.topAnchor.constraint(equalTo: v.topAnchor),
        taskInfoCollectionView.leadingAnchor.constraint(equalTo: v.leadingAnchor),
        taskInfoCollectionView.trailingAnchor.constraint(equalTo: v.trailingAnchor),
        taskInfoCollectionView.bottomAnchor.constraint(equalTo: v.bottomAnchor),
    ])
    return v
}()

回到控制器中,我使用此函数将渐变添加到采用索引和单元格的视觉效果视图

func addGradient(_ i: Int, _ cell: GroupTableCell) {
    guard let colorOne = Colors(rawValue: i)?.classicColor,
        let colorTwo = Colors(rawValue: i)?.alternativeColor else {return}
    cell.visualEffectView.contentView.setGradientBackground(colorOne: colorOne,
                                                      colorTwo: colorTwo,
                                                      name: cellLayerName)
}

我还得给 viewWillLayoutSubviews 添加一个功能。这是配置 cellForRowAt 没有的单元格。 属性 setGradients 最初设置为 true 但随后立即设置为 false,因此它不会像以前那样连续调用。

var setGradients = true    

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    if setGradients {
        configTableCells()
        setGradients = false
    }
}

func configTableCells() {
    guard let cells = self.tableView.visibleCells as? [GroupTableCell] else {return}
    for (i, cell) in cells.enumerated() {
        if shouldAddSubLayer(cell) {
            addGradient(i, cell)
        }
    }
}

然后终于在 cellForRowAt 这似乎解决了其余的问题,一切似乎 运行 顺利,没有滞后。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: GROUP_CELL_ID, for: indexPath) as! GroupTableCell
    cell.groupNameLabel.text = "Group Name"
    cell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
    addGradient(indexPath.row, cell)
    return cell
}

我尝试使用 UIView,而不是 UIVisualEffectView。但渐变再次覆盖单元格内容。所以需要UIVisualEffectView