Ios 观察一个单元格';来自视图控制器的s变量

Ios 观察一个单元格';来自视图控制器的s变量,ios,swift,Ios,Swift,我在视图控制器中有一个表视图。单击单元中的视图时,它会隐藏或显示另一个视图,并更改单元的高度 我需要在表视图上调用一个方法来重新加载此单元格。或者我需要从我的视图控制器上观察这个单元格 这就是我的代码。非常感谢您的帮助或建议。如果我的问题不清楚,请让我知道,我会尝试更详细 细胞 视图控制器 import UIKit class CheckoutViewController: UIViewController { let cellSpacingHeight:CGFloat = 30.0

我在视图控制器中有一个表视图。单击单元中的视图时,它会隐藏或显示另一个视图,并更改单元的高度

我需要在表视图上调用一个方法来重新加载此单元格。或者我需要从我的视图控制器上观察这个单元格

这就是我的代码。非常感谢您的帮助或建议。如果我的问题不清楚,请让我知道,我会尝试更详细

细胞

视图控制器

import UIKit

class CheckoutViewController: UIViewController {

    let cellSpacingHeight:CGFloat = 30.0

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        tableView.delegate = self
        tableView.dataSource = self
        tableView.separatorStyle = .none
        tableView.allowsSelection = false
        tableView.keyboardDismissMode = .onDrag

        NotificationCenter.default.addObserver(self, selector: #selector(CheckoutViewController.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(CheckoutViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)

    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: Keyboard Notifications
    @objc func keyboardWillShow(notification: NSNotification) {
        if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
            tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
        }
    }

    @objc func keyboardWillHide(notification: NSNotification) {
        UIView.animate(withDuration: 0.2, animations: {
            // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
            self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
        })
    }



}

// datasource
extension CheckoutViewController: UITableViewDataSource{

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    // Set the spacing between sections
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return cellSpacingHeight
    }

    // Make the background color show through
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerView = UIView()
        headerView.backgroundColor = UIColor.clear
        return headerView
    }

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


            let cellID = "CheckoutAddressTableViewCellReuseID"
            let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! CheckoutAddressTableViewCell

            cell.setUp(setUpCase: .billing)
            cell.headerLabel.text = "BILLING INFORMATION"

//            watch cell.sameAsButtonIsChecked

            return cell


        return UITableViewCell()
    }


}

// delegate
extension CheckoutViewController:UITableViewDelegate {

}

委托模式最适合您的情况。 您需要做几件事:

  • 创建协议:

    protocol CheckoutAddressCellActionDelegate {
        func didUpdateLayout(forCell cell: UITableViewCell)
    }
    
  • 将委托属性添加到
    CheckoutAddressTableViewCell

    weak var delegate: CheckoutAddressCellActionDelegate?
    
  • 在执行布局更改触发器时调用委托方法(可能在sameAsButtonIsChecked中):

  • 接下来,在
    CheckoutViewController
    中,首先需要在
    cellForRowAt
    方法中设置单元格的委托:

    cell.delegate = self
    
  • 最后,将扩展添加到
    CheckoutViewController
    ,该扩展实现了
    CheckoutAddressCellActionDelegate
    ,并重新加载单元格的indexPath:

    extension CheckoutViewController: CheckoutAddressCellActionDelegate {
        func didUpdateLayout(forCell cell: UITableViewCell) {
            if let indexPath = tableView.indexPath(for: cell) {
                tableView.reloadRows(at: [indexPath], with: .automatic)
            }
        }
    }
    

  • 委托模式最适合您的情况。 您需要做几件事:

  • 创建协议:

    protocol CheckoutAddressCellActionDelegate {
        func didUpdateLayout(forCell cell: UITableViewCell)
    }
    
  • 将委托属性添加到
    CheckoutAddressTableViewCell

    weak var delegate: CheckoutAddressCellActionDelegate?
    
  • 在执行布局更改触发器时调用委托方法(可能在sameAsButtonIsChecked中):

  • 接下来,在
    CheckoutViewController
    中,首先需要在
    cellForRowAt
    方法中设置单元格的委托:

    cell.delegate = self
    
  • 最后,将扩展添加到
    CheckoutViewController
    ,该扩展实现了
    CheckoutAddressCellActionDelegate
    ,并重新加载单元格的indexPath:

    extension CheckoutViewController: CheckoutAddressCellActionDelegate {
        func didUpdateLayout(forCell cell: UITableViewCell) {
            if let indexPath = tableView.indexPath(for: cell) {
                tableView.reloadRows(at: [indexPath], with: .automatic)
            }
        }
    }
    

  • 您可以创建一个协议,并将
    UIViewController
    设置为每个单元格的代理,例如:

    @objc protocol YourCellProtocol {
        cell(_ cell: CheckoutAddressTableViewCell, didChangeState state: Bool)
    }
    
    将委托属性添加到
    UITableViewCell
    子类中,并在状态更改时调用委托

    class CheckoutAddressTableViewCell: UITableViewCell {
    
        weak var delegate: YourCellProtocol?
    
        let addressFieldsHeight:CGFloat = 330
        var initialized = false;
        var sameAsButtonIsChecked:Bool = false {
            didSet {
                //call the delegate with state change
                delegate?.cell(self, didChangeState: sameAsButtonIsChecked)
    
                if sameAsButtonIsChecked  {
                    sameAsCheckboxImageView.image = #imageLiteral(resourceName: "iconCheckboxChecked")
                    addressFieldsView.isHidden = true
                    addressFieldsHeightConstraint.constant = 0
                }else{
                    sameAsCheckboxImageView.image = #imageLiteral(resourceName: "iconCheckbox")
                    addressFieldsView.isHidden = false
                    addressFieldsHeightConstraint.constant = addressFieldsHeight
                }
            }
        }
    }
    
    在您的
    UIViewController
    中,您遵守
    YourCellProtocol
    并实施它

    func cell(_ cell: CheckoutAddressTableViewCell, didChangeState state: Bool) {
        //state changed for a cell
    }
    
    cellForRowAt:
    中,您将
    UIViewController
    设置为代理:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        ...
        cell.delegate = self
        ...   
    }
    
    或者,当单元格状态随时间变化时,您也可以转到
    NotificationCenter
    发送通知的路线

    let notificatioName = Notification.Name("CellStateChanged")
    NotificationCenter.default.post(name: notificatioName, object: nil, userInfo: ["state": sameAsButtonIsChecked])
    
    然后在
    UIViewController
    中观察此通知

    let notificatioName = Notification.Name("CellStateChanged")
    NotificationCenter.default.addObserver(self, selector: #selector(cellDidChangeState(_:)), name: notificatioName, object: nil)
    
    @objc func cellDidChangeState(_ notification: Notification) {
        if let userData = notification.userInfo, let state = userData["state"] {
            //you have cells state here
        }
    }
    

    您可以创建一个协议,并将
    UIViewController
    设置为每个单元格的代理,例如:

    @objc protocol YourCellProtocol {
        cell(_ cell: CheckoutAddressTableViewCell, didChangeState state: Bool)
    }
    
    将委托属性添加到
    UITableViewCell
    子类中,并在状态更改时调用委托

    class CheckoutAddressTableViewCell: UITableViewCell {
    
        weak var delegate: YourCellProtocol?
    
        let addressFieldsHeight:CGFloat = 330
        var initialized = false;
        var sameAsButtonIsChecked:Bool = false {
            didSet {
                //call the delegate with state change
                delegate?.cell(self, didChangeState: sameAsButtonIsChecked)
    
                if sameAsButtonIsChecked  {
                    sameAsCheckboxImageView.image = #imageLiteral(resourceName: "iconCheckboxChecked")
                    addressFieldsView.isHidden = true
                    addressFieldsHeightConstraint.constant = 0
                }else{
                    sameAsCheckboxImageView.image = #imageLiteral(resourceName: "iconCheckbox")
                    addressFieldsView.isHidden = false
                    addressFieldsHeightConstraint.constant = addressFieldsHeight
                }
            }
        }
    }
    
    在您的
    UIViewController
    中,您遵守
    YourCellProtocol
    并实施它

    func cell(_ cell: CheckoutAddressTableViewCell, didChangeState state: Bool) {
        //state changed for a cell
    }
    
    cellForRowAt:
    中,您将
    UIViewController
    设置为代理:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        ...
        cell.delegate = self
        ...   
    }
    
    或者,当单元格状态随时间变化时,您也可以转到
    NotificationCenter
    发送通知的路线

    let notificatioName = Notification.Name("CellStateChanged")
    NotificationCenter.default.post(name: notificatioName, object: nil, userInfo: ["state": sameAsButtonIsChecked])
    
    然后在
    UIViewController
    中观察此通知

    let notificatioName = Notification.Name("CellStateChanged")
    NotificationCenter.default.addObserver(self, selector: #selector(cellDidChangeState(_:)), name: notificatioName, object: nil)
    
    @objc func cellDidChangeState(_ notification: Notification) {
        if let userData = notification.userInfo, let state = userData["state"] {
            //you have cells state here
        }
    }
    

    对于您的案例,使用委托是一个不错的解决方案,但我建议在单元格上使用闭包。现在,与单元相关的逻辑位于实际创建单元的同一位置,与委托模式相比,这提供了额外的可见性

    可以将以下内容添加到单元格类中

    typealias CellAction: () -> Void
    var onMyAction: CellAction?
    
    这可以是触发操作的任何函数

    func yourFuncThatTriggersTheAction() {
         onMyAction?()
    }
    
    现在在您的
    cellForRowAt

    cell.onMyAction = {
         //do whatever necessary when action is invoked
    }
    

    请注意,在cellForRowAt中使用此方法还可以解决获取触发某些操作的单元格的indexPath的问题

    对于您的案例,使用委托是一个不错的解决方案,我建议在单元格上使用闭包。现在,与单元相关的逻辑位于实际创建单元的同一位置,与委托模式相比,这提供了额外的可见性

    可以将以下内容添加到单元格类中

    typealias CellAction: () -> Void
    var onMyAction: CellAction?
    
    这可以是触发操作的任何函数

    func yourFuncThatTriggersTheAction() {
         onMyAction?()
    }
    
    现在在您的
    cellForRowAt

    cell.onMyAction = {
         //do whatever necessary when action is invoked
    }
    

    请注意,在cellForRowAt中使用此方法还可以解决获取触发某些操作的单元格的indexPath的问题

    您可以为此使用
    通知
    ,或者使用委派传递tableview的引用。您可以为此使用
    通知
    ,或者使用委派传递tableview的引用。