为啥我的 UITableView 单元格的渐变子层没有正确显示?

Posted

技术标签:

【中文标题】为啥我的 UITableView 单元格的渐变子层没有正确显示?【英文标题】:Why isn’t the gradient sublayer of my UITableView cell displaying properly?为什么我的 UITableView 单元格的渐变子层没有正确显示? 【发布时间】:2020-05-16 06:16:48 【问题描述】:

我有一个带有自定义单元格的UITableView,我使用渐变作为背景。我在 Swift Playgrounds 中编码,当我运行 Playground 时,带有渐变的单元格没有圆角。

另外,当我在表格中上下滚动时,有时单元格中的渐变会突然“分成两半”(见下图)。我做错了什么?

我的代码:

class ViewController: UITableViewController 

    // Array that holds the messages
    var textMessages = [String]()
    let sampleTextField =  UITextField(frame: CGRect(x: 20, y: 20, width: 300, height: 40))

    override func viewDidLoad() 
        super.viewDidLoad()

        // Reguster custom cell
        tableView.register(ChatMessageCell.self, forCellReuseIdentifier: "cell_1")
        // Turn off seperators
        tableView.separatorStyle = .none
        // Set header, footer height
        tableView.sectionFooterHeight = 75
        tableView.sectionHeaderHeight = 75
    

    // Custom header
    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
        let customView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 75))
        customView.backgroundColor = UIColor(white: 0.9, alpha: 1)
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 75))
        button.setTitle("Submit", for: .normal)

        customView.addSubview(button)
        return customView
    

    //Custom footer
    override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView?
        let customView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 75))
        customView.backgroundColor = UIColor(white: 0.9, alpha: 1)

        sampleTextField.placeholder = "Enter text here"
        sampleTextField.font = UIFont.systemFont(ofSize: 15)
        sampleTextField.borderStyle = .none
        sampleTextField.backgroundColor = .white
        sampleTextField.autocorrectionType = UITextAutocorrectionType.no
        sampleTextField.keyboardType = UIKeyboardType.default
        sampleTextField.returnKeyType = UIReturnKeyType.done
        sampleTextField.clearButtonMode = UITextField.ViewMode.whileEditing
        sampleTextField.contentVerticalAlignment = UIControl.ContentVerticalAlignment.center
        sampleTextField.layer.shadowRadius = 10
        sampleTextField.layer.shadowColor = UIColor.black.cgColor
        sampleTextField.layer.shadowOffset = CGSize(width: 0, height: 0)
        sampleTextField.layer.shadowOpacity = 0.5
        sampleTextField.layer.cornerRadius = 16
        sampleTextField.layer.masksToBounds = true
        let buttonZ = UIButton(type: .custom)
        buttonZ.setImage(UIImage(named: "send.png"), for: .normal)
        buttonZ.imageEdgeInsets = UIEdgeInsets(top: 0, left: -16, bottom: 0, right: 0)
        buttonZ.frame = CGRect(x: CGFloat(sampleTextField.frame.size.width - 25), y: CGFloat(5), width: CGFloat(25), height: CGFloat(25))
        buttonZ.backgroundColor = .blue
        sampleTextField.rightView = buttonZ
        sampleTextField.rightViewMode = .always
        buttonZ.addTarget(self, action: #selector(updateView), for: .touchUpInside)

        customView.layer.cornerRadius = 20
        customView.layer.shadowRadius = 5.0
        customView.layer.shadowColor = UIColor.black.cgColor
        customView.layer.shadowOffset = CGSize(width: 0, height: 0)
        customView.layer.shadowOpacity = 0.8

        customView.addSubview(sampleTextField)
        return customView
    

    @objc func updateView()
        adddatextbruh()
    

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return textMessages.count
    

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell_1", for: indexPath) as! ChatMessageCell
        cell.selectionStyle = .none

        if indexPath.row % 2 == 1
            cell.messageLabel.text = textMessages[indexPath.row]

            cell.bubbleBackgroundView.backgroundColor = UIColor(white: 0.9, alpha: 1)
            return cell
        else
            cell.messageLabel.text = textMessages[indexPath.row]
            //cell.setupConstraints(side: 0)
            //cell.bubbleBackgroundView.backgroundColor = .blue
            var gradientLayer : CAGradientLayer = 
                let layer = CAGradientLayer()
                layer.colors = [UIColor.red, UIColor.blue].map$0.cgColor
                layer.startPoint = CGPoint(x: 0.5, y: 1.0)
                layer.endPoint = CGPoint(x: 0.5, y: 0.0)
                layer.locations = [NSNumber(floatLiteral: 0.0), NSNumber(floatLiteral: 1.0)]
                layer.frame = cell.bubbleBackgroundView.bounds
                layer.masksToBounds = true
                return layer
            ()
            cell.bubbleBackgroundView.layer.insertSublayer(gradientLayer, at: 0)
            /*
             let gradientLayer = CAGradientLayer()
             let colorTop : UIColor = .red
             let colorBottom : UIColor = .blue
             gradientLayer.colors = [colorTop.cgColor, colorBottom.cgColor]
             gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
             gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
             gradientLayer.locations = [NSNumber(floatLiteral: 0.0), NSNumber(floatLiteral: 1.0)]
             gradientLayer.frame = cell.bubbleBackgroundView.bounds

             cell.bubbleBackgroundView.layer.insertSublayer(gradientLayer, at: 0)
             */
            return cell
        
    
    //let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! ChatMessageCell
    //        cell.textLabel?.text = "We want to provide a longer string that is actually going to wrap onto the next line and maybe even a third line."
    //        cell.textLabel?.numberOfLines = 0
    func adddatextbruh()
        let botInstance = Bot()
        var writtenText = sampleTextField.text

        textMessages.append(writtenText!)

        tableView.beginUpdates()
        tableView.insertRows(at: [
            (NSIndexPath(row: textMessages.count-1, section: 0) as IndexPath)], with: .automatic)
        tableView.endUpdates()
        tableView.scrollToRow(at: IndexPath(row: textMessages.count-1, section: 0), at: UITableView.ScrollPosition.bottom, animated: true)
        var botReply = botInstance.replyTo(writtenText!)

        textMessages.append(botReply)

        tableView.beginUpdates()
        tableView.insertRows(at: [
            (NSIndexPath(row: textMessages.count-1, section: 0) as IndexPath)], with: .automatic)
        tableView.endUpdates()
        tableView.scrollToRow(at: IndexPath(row: textMessages.count-1, section: 0), at: UITableView.ScrollPosition.bottom, animated: true)

        textMessages.append(getSent().description)

        tableView.beginUpdates()
        tableView.insertRows(at: [
            (NSIndexPath(row: textMessages.count-1, section: 0) as IndexPath)], with: .automatic)
        tableView.endUpdates()
        tableView.scrollToRow(at: IndexPath(row: textMessages.count-1, section: 0), at: UITableView.ScrollPosition.bottom, animated: true)
    

【问题讨论】:

【参考方案1】:

cellForItem 中的代码似乎很长。将来你甚至会经历它。如果您为UITableViewCell 创建一个subClass 并在其中进行自定义会更好。为了帮助您,我发布了使gradientLayerUITableViewCell 中正常工作所需的最低代码。玩弄它以获得您想要的结果。将其发布到您的 Xcode 游乐场,并在您自己进行更改时查看结果。关键是随着单元格帧的更新不断更新梯度层。

import UIKit
import PlaygroundSupport

class ViewController: UITableViewController 

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int  10 

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        ChatCell()
    


class ChatCell: UITableViewCell 

    let gradientLayer = CAGradientLayer()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) 
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        gradientLayer.colors = [UIColor.red.cgColor, UIColor.blue.cgColor]
        layer.addSublayer(gradientLayer)
    

    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    

    override func layoutIfNeeded() 
        super.layoutIfNeeded()

        gradientLayer.frame = bounds
    


PlaygroundPage.current.liveView = ViewController()

【讨论】:

以上是关于为啥我的 UITableView 单元格的渐变子层没有正确显示?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我无法使用具有自动布局的渐变子层来定位我的视图?它没有出现

为啥 UITableView 的最后一个单元格的高度用于剩余的空单元格?

为啥我的渐变层覆盖了我的 collectionView 单元格?

为啥 UITableView 自定义单元格的第一个单元格总是在 Xcode 中的动作事件上被调用两次

为啥我的 UITableView 的“点击编辑”功能很慢?

UITableView 中自定义单元格的 UITapGestureRecognizer