1

I want to create an hourly calendar view that is relatively basic, but similar to Apple's native calendar view. How do you add labels to be in line with the row/cell separators, and not contained in a cell. Like this:

enter image description here

Is there a property that lets you add a label to the lines? Do the labels have to be placed outside of the table view? Or is there a separate table that occurs?

In terms of creating colored blocks to represent events on the calendar, what would be the best way to go about doing this? Would it just be a CGRect in a prototype cell? Would you need to create separate xib files?

Thanks in advance for the help, I am still new to learning Swift!

user3628240
  • 877
  • 1
  • 23
  • 41
  • Possible duplicate of [How to customize tableView separator in iPhone](https://stackoverflow.com/questions/1374990/how-to-customize-tableview-separator-in-iphone) – Mo Abdul-Hameed Jan 07 '18 at 09:40

1 Answers1

1

It's not possible (or technically, it would be possible, but the overhead is too high, considering your other options).

Instead of using cell separators, set separatorStyle = .none, and draw the line in the cell (e.g., as a UIView with view.height = 1 and view.backgroundColor = .grey) and normally add the label in the cell.

Basically the solution is very simple: disable standard separator lines, and rather draw separator inside the cell (bottom or top) along with the labels. That's how I've been doing things when the client asked for some custom fancy separators - I added a custom line at the bottom of the cell and used the rest of the cell's contentView as for the cell's content.

EDIT

You can use a following example to start with (note that this is just one of several different approaches how to manage it):

class TimeCellViewController: UITableViewController {
    override func loadView() {
        super.loadView()

        // you can use UITableViewAutomaticDimension instead of static height, if
        // there will be variable heights that you don't know upfront
        // https://stackoverflow.com/a/18746930/2912282
        // or mine:
        // https://stackoverflow.com/a/47963680/2912282
        tableView.rowHeight = 80
        tableView.estimatedRowHeight = 80

        tableView.separatorStyle = .none

        // to allow scrolling below the last cell
        tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 40))

        tableView.register(TimeCell.self, forCellReuseIdentifier: "timeCell")
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "timeCell", for: indexPath) as! TimeCell
        if indexPath.row > 0 {
            cell.topTime = "\(indexPath.row):00"
        } else {
            cell.topTime = ""
        }
        cell.bottomTime = "\(indexPath.row + 1):00"
        return cell
    }
}

class TimeCell: UITableViewCell {
    // little "hack" using two labels to render time both above and below the cell
    private let topTimeLabel = UILabel()
    private let bottomTimeLabel = UILabel()

    private let separatorLine = UIView()

    var topTime: String = "" {
        didSet {
            topTimeLabel.text = topTime
        }
    }
    var bottomTime: String = "" {
        didSet {
            bottomTimeLabel.text = bottomTime
        }
    }

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

        selectionStyle = .none

        contentView.addSubview(topTimeLabel)
        contentView.addSubview(bottomTimeLabel)
        contentView.addSubview(separatorLine)


        topTimeLabel.textColor = UIColor.gray
        topTimeLabel.textAlignment = .right
        bottomTimeLabel.textColor = UIColor.gray
        bottomTimeLabel.textAlignment = .right
        separatorLine.backgroundColor = UIColor.gray

        bottomTimeLabel.translatesAutoresizingMaskIntoConstraints = false
        topTimeLabel.translatesAutoresizingMaskIntoConstraints = false
        separatorLine.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            bottomTimeLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0),
            bottomTimeLabel.centerYAnchor.constraint(equalTo: self.bottomAnchor),
            bottomTimeLabel.widthAnchor.constraint(equalToConstant: 50),
            topTimeLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0),
            topTimeLabel.centerYAnchor.constraint(equalTo: self.topAnchor),
            topTimeLabel.widthAnchor.constraint(equalToConstant: 50),
            separatorLine.leftAnchor.constraint(equalTo: bottomTimeLabel.rightAnchor, constant: 8),
            separatorLine.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            separatorLine.heightAnchor.constraint(equalToConstant: 1),
            separatorLine.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0),
            ])

        // if you use UITableViewAutomaticDimension instead of static height,
        // you will have to set priority of one of the height constraints to 999, see
        // https://stackoverflow.com/q/44651241/2912282
        // and
        // https://stackoverflow.com/a/48131525/2912282
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90
  • Also headers/footers can be used to achieve this – iWheelBuy Jan 07 '18 at 09:51
  • 1
    yep, but then he would have to go section per cell.. although in his particular case that does not have to be problem.. – Milan Nosáľ Jan 07 '18 at 09:52
  • For a calendar with blocks of events that would span multiple cells/rows, would this solution still work? Wouldn't the top of each cell have a small blank then, which would mean a block would have white space where the top of the cell is too? – user3628240 Jan 08 '18 at 05:57
  • why wouldn't it? in this approach, the whole cell is under your control - if you implement the cell so that there will be a blank space, there will be a blank space. If you implement it so that there is no blank space, there will not be a blank space. – Milan Nosáľ Jan 08 '18 at 08:41
  • yeah, I see what you mean.. well, it's not gonna be easy, but you can do a little hack that will make it look like that is truly a separator by rendering the label in both cells (then it would look like the label is exactly between the two cells).. I'll update my answer to include a tiny example for you to start with – Milan Nosáľ Jan 08 '18 at 08:53
  • Sorry, I just got back to my computer, but your solution did work. Thank you very much for the help, I really appreciate it! – user3628240 Jan 09 '18 at 08:17