iOS Swift, Update UITableView custom cell label outside of tableview CellForRow using tag

前端 未结 3 518
终归单人心
终归单人心 2020-12-28 11:30

Setup (Swift 1.2 / iOS 8.4):

I have UITableView custom cell (identifier = Cell) inside UIViewController. Have two buttons (increment/decrement count) and a label (di

相关标签:
3条回答
  • 2020-12-28 11:36

    Use tableView.reloadData() to reload your tableView content each time you click a button.

    let text = "something"
     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
        let cell:FoodTypeTableViewCell = self.tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! FoodTypeTableViewCell
    
        cell.addBtn.tag = indexPath.row // Button 1
        cell.addBtn.addTarget(self, action: "addBtn:", forControlEvents: .TouchUpInside)
    
        cell.subBtn.tag = indexPath.row // Button 2
        cell.subBtn.addTarget(self, action: "subBtn:", forControlEvents: .TouchUpInside)
    
        cell.countLabel.text = something
        return cell
    }
    
    func addBtn(sender: AnyObject) -> Int {
        let button: UIButton = sender as! UIButton
        count = 1 + count
        println(count)
        something = "\(count)"
        self.tableView.reloadData()
        return count
    }
    
    func subBtn(sender: AnyObject) -> Int {
        let button: UIButton = sender as! UIButton
        if count == 0 {
            println("Count zero")
        } else {
            count = count - 1
        }
        println(count)
        something = "\(count)"
        self.tableView.reloadData()
        return count
    }
    

    Update1

    After your comments ... you have an array (one value for each food) like this, and whenever you click on a button, you take the index of the row the contains that button, then use that index to retrive the value of count from your array, then reload the table view content.

    0 讨论(0)
  • 2020-12-28 11:47

    Here is a solution that doesn't require tags. I'm not going to recreate the cell exactly as you want, but this covers the part you are asking about.

    Using Swift 2 as I don't have Xcode 6.x anymore.

    Let's start with the UITableViewCell subclass. This is just a dumb container for a label that has two buttons on it. The cell doesn't actually perform any specific button actions, it just passes on the call to closures that are provided in the configuration method. This is part of MVC. The view doesn't interact with the model, just the controller. And the controller provides the closures.

    import UIKit
    
    typealias ButtonHandler = (Cell) -> Void
    
    class Cell: UITableViewCell {
    
        @IBOutlet private var label: UILabel!
        @IBOutlet private var addButton: UIButton!
        @IBOutlet private var subtractButton: UIButton!
    
        var incrementHandler: ButtonHandler?
        var decrementHandler: ButtonHandler?
    
        func configureWithValue(value: UInt, incrementHandler: ButtonHandler?, decrementHandler: ButtonHandler?) {
            label.text = String(value)
            self.incrementHandler = incrementHandler
            self.decrementHandler = decrementHandler
        }
    
    
        @IBAction func increment(sender: UIButton) {
            incrementHandler?(self)
        }
    
    
        @IBAction func decrement(sender: UIButton) {
            decrementHandler?(self)
        }
    }
    

    Now the controller is just as simple

    import UIKit
    
    class ViewController: UITableViewController {
    
        var data: [UInt] = Array(count: 20, repeatedValue: 0)
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
        }
    
        override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            return 1
        }
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return data.count
        }
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! Cell
    
            cell.configureWithValue(data[indexPath.row], incrementHandler: incrementHandler(), decrementHandler: decrementHandler())
    
            return cell
        }
    
        private func incrementHandler() -> ButtonHandler {
            return { [unowned self] cell in
                guard let row = self.tableView.indexPathForCell(cell)?.row else { return }
                self.data[row] = self.data[row] + UInt(1)
    
                self.reloadCellAtRow(row)
            }
        }
    
        private func decrementHandler() -> ButtonHandler {
            return { [unowned self] cell in
                guard
                    let row = self.tableView.indexPathForCell(cell)?.row
                    where self.data[row] > 0
                    else { return }
                self.data[row] = self.data[row] - UInt(1)
    
                self.reloadCellAtRow(row)
            }
        }
    
        private func reloadCellAtRow(row: Int) {
            let indexPath = NSIndexPath(forRow: row, inSection: 0)
    
            tableView.beginUpdates()
            tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
            tableView.endUpdates()
        }
    
    }
    

    When the cell is dequeued, it configures the cell with the value to show in the label and provides the closures that handle the button actions. These controllers are what interact with the model to increment and decrement the values that are being displayed. After changing the model, it reloads the changed cell in the tableview.

    The closure methods take a single parameter, a reference to the cell, and from this it can find the row of the cell. This is a lot more de-coupled than using tags, which are a very brittle solution to knowing the index of a cell in a tableview.

    You can download a full working example (Requires Xcode7) from https://bitbucket.org/abizern/so-32931731/get/ce31699d92a5.zip

    0 讨论(0)
  • 2020-12-28 11:48

    I have never seen anything like this before so I am not sure if this will be the correct way to do. But I got the intended functionality using the bellow code:

    For people who find it difficult to understand: The only problem we have in this is to refer to the TableView Cell. Once you figure out a way to refer the cell, you can interact with the cell components.

    func addBtn(sender: AnyObject) -> Int {
        let button: UIButton = sender as! UIButton
    
        let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0) // This defines what indexPath is which is used later to define a cell
        let cell = tableView.cellForRowAtIndexPath(indexPath) as! FoodTypeTableViewCell! // This is where the magic happens - reference to the cell
    
        count = 1 + count
        println(count)
        cell.countLabel.text = "\(count)" // Once you have the reference to the cell, just use the traditional way of setting up the objects inside the cell.
        return count
    }
    
    func subBtn(sender: AnyObject) -> Int {
        let button: UIButton = sender as! UIButton
    
        let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)
        let cell = tableView.cellForRowAtIndexPath(indexPath) as! FoodTypeTableViewCell!
    
        if count == 0 {
            println("Count zero")
        } else {
            count = count - 1
        }
    
        cell.countLabel.text = "\(count)"
        println(count)
        return count
    }
    

    I hope someone will benefit from this.

    PLEASE CORRECT ME IF THERE IS SOME PROBLEM IN THIS SOLUTION OR THERE IS A BETTER/PROPER WAY TO DO THIS.

    0 讨论(0)
提交回复
热议问题