找到一个 tableView 单元格 superView

finding a tableView cells superView

我正在尝试创建一个范围滑块,其中包含表示滑块句柄值的标签。我启用了滑块,但是当我尝试将标签添加到滑块子视图时,我的应用程序因错误

而崩溃

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

滑块位于 tableViewCell 内部,我正在使用以下代码在 tableView VC 中初始化此单元格,

if indexPath.section == 2 {
        let costRangeCell = AgeRangeCell(style: .default, reuseIdentifier: nil)

        let contentView = costRangeCell.rangeSlider.superview! 

// 我的 contentView 声明是我的应用崩溃的地方。

        costRangeCell.rangeSlider.minimumValue = 0
        costRangeCell.rangeSlider.maximumValue = 100
        costRangeCell.rangeSlider.lowValue = 0
        costRangeCell.rangeSlider.highValue = 100
        costRangeCell.rangeSlider.minimumDistance = 20

        let lowLabel = UILabel()
        contentView.addSubview(lowLabel)
        lowLabel.textAlignment = .center
        lowLabel.frame = CGRect(x:0, y:0, width: 60, height: 20)

        let highLabel = UILabel()
        contentView.addSubview(highLabel)
        highLabel.textAlignment = .center
        highLabel.frame = CGRect(x: 0, y: 0, width: 60, height: 20)

        costRangeCell.rangeSlider.valuesChangedHandler = { [weak self] in
          
        let lowCenterInSlider = CGPoint(x:costRangeCell.rangeSlider.lowCenter.x, y: costRangeCell.rangeSlider.lowCenter.y - 30)
        let highCenterInSlider = CGPoint(x:costRangeCell.rangeSlider.highCenter.x, y: costRangeCell.rangeSlider.highCenter.y - 30)
        let lowCenterInView = costRangeCell.rangeSlider.convert(lowCenterInSlider, to: contentView)
        let highCenterInView = costRangeCell.rangeSlider.convert(highCenterInSlider, to: contentView)

        lowLabel.center = lowCenterInView
        highLabel.center = highCenterInView
        lowLabel.text = String(format: "%.1f", costRangeCell.rangeSlider.lowValue)
        highLabel.text = String(format: "%.1f", costRangeCell.rangeSlider.highValue)
        }
        
        costRangeCell.rangeSlider.addTarget(self, action: #selector(handleMinAgeChange), for: .valueChanged)
        let minAge = user?.minSeekingCost ?? SettingsViewController.defaultMinSeekingCost
        costRangeCell.rangeLabel.text = " $\(minAge)"
        return costRangeCell
    }

我可以通过其他方式访问单元格范围滑块 superView 吗?

年龄范围class,

class AgeRangeCell: UITableViewCell {

let rangeSlider: AORangeSlider = {
    let slider = AORangeSlider()
    slider.minimumValue = 20
    slider.maximumValue = 200
    return slider
}()


let rangeLabel: UILabel = {
    let label = costRangeLabel()
    label.text = "$ "
    return label
}()




class costRangeLabel: UILabel {
    override var intrinsicContentSize: CGSize {
        return .init(width: 80, height: 50)
    }
}

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    
    contentView.isUserInteractionEnabled = true

    let overallStackView = UIStackView(arrangedSubviews: [
        UIStackView(arrangedSubviews: [rangeLabel, rangeLabel]),
        ])
    overallStackView.axis = .horizontal
    overallStackView.spacing = 16
    addSubview(overallStackView)
    overallStackView.anchor(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor, padding: .init(top: 16, left: 16, bottom: 16, right: 16))
    
}

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

  }

AORangeSlider 是自定义滑块。

看过 AORangeSlider...

您想在自定义单元格中实现标签跟踪... 在您的控制器中class。

这是一个简单的实现,基于您在问题中提供的代码:

class AgeRangeCell: UITableViewCell {
    let rangeSlider: AORangeSlider = {
        let slider = AORangeSlider()
        slider.minimumValue = 0
        slider.maximumValue = 100
        return slider
    }()

    let lowLabel = UILabel()
    let highLabel = UILabel()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        
        lowLabel.textAlignment = .center
        lowLabel.frame = CGRect(x:0, y:0, width: 60, height: 20)
        
        highLabel.textAlignment = .center
        highLabel.frame = CGRect(x: 0, y: 0, width: 60, height: 20)
        
        [rangeSlider, lowLabel, highLabel].forEach {
            contentView.addSubview([=10=])
        }
        
        rangeSlider.translatesAutoresizingMaskIntoConstraints = false
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            rangeSlider.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            rangeSlider.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            rangeSlider.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            rangeSlider.heightAnchor.constraint(equalToConstant: 40.0),
        ])
        
        // avoid auto-layout complaints
        let c = rangeSlider.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0)
        c.priority = UILayoutPriority(rawValue: 999)
        c.isActive = true


        rangeSlider.valuesChangedHandler = { [weak self] in
            guard let `self` = self else {
                return
            }
            let lowCenterInSlider = CGPoint(x:self.rangeSlider.lowCenter.x, y: self.rangeSlider.lowCenter.y - 30)
            let highCenterInSlider = CGPoint(x:self.rangeSlider.highCenter.x, y: self.rangeSlider.highCenter.y - 30)
            let lowCenterInView = self.rangeSlider.convert(lowCenterInSlider, to: self.contentView)
            let highCenterInView = self.rangeSlider.convert(highCenterInSlider, to: self.contentView)
            
            self.lowLabel.center = lowCenterInView
            self.highLabel.center = highCenterInView
            self.lowLabel.text = String(format: "%.1f", self.rangeSlider.lowValue)
            self.highLabel.text = String(format: "%.1f", self.rangeSlider.highValue)
        }
        
    }
}

class RangeTableViewController: UITableViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // register your "slider" cell
        tableView.register(AgeRangeCell.self, forCellReuseIdentifier: "ageRangeCell")

        // register any other cell classes you'll be using
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "plainCell")

    }
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 3
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 2 {
            return 1
        }
        return 2
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        if indexPath.section == 2 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "ageRangeCell", for: indexPath) as! AgeRangeCell

            cell.rangeSlider.minimumValue = 0
            cell.rangeSlider.maximumValue = 100
            cell.rangeSlider.lowValue = 0
            cell.rangeSlider.highValue = 100
            cell.rangeSlider.minimumDistance = 20

            return cell
        }
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "plainCell", for: indexPath)
        cell.textLabel?.text = "\(indexPath)"
        return cell
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "Section Header: \(section)"
    }
}

该代码将产生这个: