【问题标题】:Show/hide table view cell using UISwitch使用 UISwitch 显示/隐藏表格视图单元格
【发布时间】:2019-03-21 20:42:30
【问题描述】:

我想使用UISwitch 在动态表格视图中显示/隐藏 tableViewCell。 UISwitch 定义在一个 `UITableViewCell.

@IBOutlet weak var switchState: UISwitch!

在另一个文件中我想说如果此开关打开,行数将为 5,否则应为 4

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    let test = PopupViewCell()
    if test.switchState?.isOn == true {
        detailsTableView.reloadData()
        return 5
    } else {
        return 4
    }
}

但它不起作用,它总是显示 `return 4。 我也测试一下:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    let test = PopupViewCell()
    if test.switchState.isOn {
        detailsTableView.reloadData()
        return 5
    } else {
        return 4
    }
}

但是我会得到这个错误:

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

我不确定在此过程之前是否必须使用一些操作功能,如果有人可以帮助我,我将不胜感激。

【问题讨论】:

  • 细胞不应该保存它们的数据源。您必须与您的对象拥有单独的数据源数组,其中包含以下内容:对象 1 - 可见,对象 2 - 不可见,...然后根据对象的属性设置出口值。您的错误的另一个原因是,您只是在初始化您的单元,并且您的插座没有正确连接,因为您初始化错误。动态单元格应出列。

标签: swift uitableview uiswitch


【解决方案1】:

最适合初学者的方式是委托委托。当 Switch 单元检测到 .valueChanged 事件时,它应该将其转发给委托人。代理依次更新其是否显示开关的模型,然后重新加载tableView

这是一个 Playground 示例:

import UIKit
import PlaygroundSupport

protocol SwitchDelegate: class {
    func toggle(isOn: Bool)
}

class SwitchCell: UITableViewCell {
    private lazy var switchControl: UISwitch = {
        let switchControl = UISwitch()
        contentView.addSubview(switchControl)
        switchControl.translatesAutoresizingMaskIntoConstraints = false
        switchControl.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 12).isActive = true
        switchControl.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
        switchControl.addTarget(self, action: #selector(toggleSwitch(_:)), for: .valueChanged)
        return switchControl
    }()
    private weak var delegate: SwitchDelegate?
    override func awakeFromNib() {
        super.awakeFromNib()

    }
    func configure(isOn: Bool, delegate: SwitchDelegate) {
        switchControl.isOn = isOn
        self.delegate = delegate
    }
    @objc private func toggleSwitch(_ sender: UISwitch) {
        delegate?.toggle(isOn: sender.isOn)
    }
}

class ViewController: UITableViewController {
    private let data = (0..<5).map { $0 + 1 }
    private var isOn = true
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: String(describing: UITableViewCell.self))
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count + (isOn ? 1 : 0)
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if isOn && indexPath.row == 0 {
            let switchCell = SwitchCell(style: .default, reuseIdentifier: String(describing: SwitchCell.self))
            switchCell.configure(isOn: isOn, delegate: self)
            return switchCell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UITableViewCell.self), for: indexPath)
            let dataIndex = indexPath.row - (isOn ? 1 : 0)
            cell.textLabel?.text = String(describing: data[dataIndex])
            return cell
        }
    }
}

extension ViewController: SwitchDelegate {
    func toggle(isOn: Bool) {
        self.isOn = isOn
        tableView.reloadData()
    }
}

PlaygroundPage.current.liveView = ViewController()

【讨论】:

  • 我更喜欢闭包而不是代表
  • 非常感谢乔希的帮助,我想这是我的答案。只是一件事,我在我的项目中实现了你的代码,只是有一个问题,你以编程方式创建一个 UISwitch 并在其变量中添加“addTarget”,但是由于我已经通过插座定义了 UISwitch,我不明白如何使用 addTarget带插座 UISwitch。你能帮我吗?
  • 要从 nib 或情节提要中添加目标,您可以 ctrl+从按钮拖动到代码中并创建 IBAction。或者,即使您在情节提要中创建按钮,您仍然可以像上面那样在代码中执行此操作。 (在这种情况下,将 add target 语句放在 IBOutlet 上的 viewDidLoad 或 didSet 中——任何一个都可以)。