Search code examples
iosuitableviewpaintcode

Add custom class to UIView in the UITableView


I have made some icon with the paint code app:

class addIconView: UIView {
    override func draw(_ rect: CGRect) {
      TodayIcon.draw(frame: rect)
    }
 }

I also add the configuration of the cells in another class:

class OptionsTableCell {
    var icon: UIView
    var label: String

    init(icon: UIView, label: String) {
        self.icon = icon
        self.label = label
    }
}

Then I added a UIView in the prototype cell in a TableView. I used this array to update icons of the cell:

var optionsArray: [OptionsTableCell] = []

func createOptionsArray() -> [OptionsTableCell] {

    var cell: [OptionsTableCell] = []

    let addIcon = OptionsTableCell(icon: addIconView(), label: "Add")

    cell.append(addIcon)

    return cell
}

I just added addIconView() to update the icon of the cell. I think it's wrong.

How can I update the custom class of an UIView to change the icon inside it?


Solution

  • Instead of using a generic UIView in the cell, subclass it into a new class that encapsulates the types of icons to be displayed. Consider this example:

    UIView subclass that encapsulates the icon logic around PaintCode. Notice the Option enum and the @IBDesignable property (allows for live-rendering in Interface Builder):

    import UIKit
    
    @IBDesignable class OptionsView: UIView {
    
        // MARK: - Properties
    
        // Allowed options.
        enum Option {
            case star, tree
        }
    
        // Option that should currently be displayed. Default is .star (for no particular reason).
        var currentOption: Option = .star {
            didSet {
                setNeedsDisplay() // Force redrawing.
            }
        }
    
        // MARK: - Lifecycle
    
        override func draw(_ rect: CGRect) {
            drawIcon(rect)
        }
    }
    
    // MARK: - Private
    
    private extension OptionsView {
    
        /// Logic to decide which icon to display.
        func drawIcon(_ rect: CGRect) {
            switch currentOption {
            case .star:
                StyleKit.drawStarIcon(frame: rect)
            case .tree:
                StyleKit.drawTreeIcon(frame: rect)
            }
        }
    }
    

    Storyboard configuration: custom UITableViewController + custom UITableViewCell with the custom UIView (notice the class attribute of type OptionsView):

    setup

    Connect the UILabel and the OptionsView to your CustomCell. Implementation example (notice the var option):

    import UIKit
    
    class CustomCell: UITableViewCell {
    
        // MARK: - Public  Properties
    
        // Option that should currently be displayed. Default is .star (for no particular reason).
        var option: OptionsView.Option = .star {
            didSet {
                iconView.currentOption = option
                updateLabelText()
            }
        }
    
        // MARK: - Private Properties
    
        @IBOutlet private weak var iconView: OptionsView!
        @IBOutlet private weak var label: UILabel!
    }
    
    // MARK: - Private
    
    private extension CustomCell {
    
        func updateLabelText() {
            switch option {
            case .star:
                label.text = "Star"
            case .tree:
                label.text = "Tree"
            }
        }
    }
    

    Finally, in your custom UITableViewController:

    import UIKit
    
    class TableViewController: UITableViewController {
    
        // MARK: - Table view data source
    
        override func numberOfSections(in tableView: UITableView) -> Int {
            return 1 // Hardcoded in this example.
        }
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 40 // Hardcoded in this example.
        }
    
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            if let customCell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as? CustomCell {
    
                // Logic around which option to display
                if indexPath.row < 20 {
                    customCell.option = .star
                } else {
                    customCell.option = .tree
                }
    
                return customCell
            }
    
            // Fallback.
            return UITableViewCell()
        }
    }
    

    Final result:

    example

    Refer to this project for the entire code (sixth test):
    https://github.com/backslash-f/paintcode-tests