Gurpreet Paul
Gurpreet Paul

Reputation: 17

How can custom tableview cells be made in swift playground?

In swift playground (not in a project) Could you please give me a hint about how to do this please?enter image description here

Upvotes: 0

Views: 1008

Answers (2)

Chris Conover
Chris Conover

Reputation: 9039

Full credit to @Rob, this is a tweak of his answer, but after trying to directly add the cell to a table view to no avail (cells seem to ignore explicit sizing), I reduced his view controller to a generic one for ease of re-use.

    class DashboardViewController<T: UITableViewCell>: UITableViewController {

        override func viewDidLoad() {
            super.viewDidLoad()

            tableView.register(T.self, forCellReuseIdentifier: "Cell")

            // set it up to let auto-layout resize the cell
            tableView.rowHeight = UITableViewAutomaticDimension
            tableView.estimatedRowHeight = 44
        }

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

        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! T
            configure(cell)
            return cell
        }

        var configure: ((T) -> ())!

        static func with(configuration: ((T) -> ())!) {
            let controller = DashboardViewController<T>()
            controller.configure = configuration
            PlaygroundPage.current.liveView = controller
        }
    }

    // usage:
    DashboardViewController<MyCustomCell>.with() { cell in
        let model = MyCellModel()
        cell.model = model }

Upvotes: 1

Rob
Rob

Reputation: 437552

You have to implement init(style:reuseIdentifier:) in your custom class to define subviews and constraints programmatically.

Thus:

import UIKit
import PlaygroundSupport

class CustomCell: UITableViewCell {
    weak var label1: UILabel!
    weak var label2: UILabel!

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        let label1 = UILabel()
        label1.translatesAutoresizingMaskIntoConstraints = false
        label1.font = .preferredFont(forTextStyle: .title1)
        label1.backgroundColor = #colorLiteral(red: 0.572549045085907, green: 0.0, blue: 0.23137255012989, alpha: 1.0)
        label1.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
        contentView.addSubview(label1)
        self.label1 = label1

        let label2 = UILabel()
        label2.translatesAutoresizingMaskIntoConstraints = false
        label2.font = .preferredFont(forTextStyle: .title1)
        label2.backgroundColor = #colorLiteral(red: 0.0901960805058479, green: 0.0, blue: 0.301960796117783, alpha: 1.0)
        label2.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
        contentView.addSubview(label2)
        self.label2 = label2

        NSLayoutConstraint.activate([
            label1.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
            label2.leadingAnchor.constraint(equalTo: label1.trailingAnchor, constant: 10),
            contentView.trailingAnchor.constraint(equalTo: label2.trailingAnchor, constant: 10),
            label1.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
            label2.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
            contentView.bottomAnchor.constraint(equalTo: label1.bottomAnchor, constant: 10),
            contentView.bottomAnchor.constraint(equalTo: label2.bottomAnchor, constant: 10),
            label1.widthAnchor.constraint(equalTo: label2.widthAnchor)
            ])
    }

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

And then you'd have a standard UITableViewController which registers this class and uses it:

class ViewController: UITableViewController {
    var objects: [String] = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .spellOut
        return Array(0 ..< 1000).flatMap { formatter.string(from: NSNumber(value: $0)) }
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")

        // set it up to let auto-layout resize the cell

        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 44
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return objects.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell

        cell.label1.text = objects[indexPath.row]
        cell.label2.text = "Row \(indexPath.row)"

        return cell
    }
}

PlaygroundPage.current.liveView = ViewController()

Now that just creates a simple view like this:

enter image description here

That's not terribly pretty, but I set the background colors like I did, just so you can see that the frames are set appropriately. You'd obviously adjust your init(style:reuseIdentifier:) to create subviews more to your liking.


If you want the standard cell, then you don't need to have a custom cell subclass, but you can just use UITableViewCell:

import UIKit
import PlaygroundSupport

class ViewController: UITableViewController {
    var objects: [String] = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .spellOut
        return Array(0 ..< 1000).flatMap { formatter.string(from: NSNumber(value: $0)) }
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 44
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return objects.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        cell.textLabel?.text = objects[indexPath.row]

        return cell
    }
}

PlaygroundPage.current.liveView = ViewController()

On the iPad, that yields:

enter image description here

On Playground in Xcode, it yields:

enter image description here

Upvotes: 5

Related Questions