Reputation: 87
I've got a UICollectionViewCell
that has a UIView inside. When dequeueing the cell, I initialise it with the necessary data. After the data is initialised, inside the UIView
, there is some drawing that is meant to be displayed. However, nothing appears.
Initially, this was all inside UICollectionView
cellForItemAt
method and drew the lines, but it should've been inside a UIView so I subclassed it and placed the code in there. This is where it stopped working.
I've tried overriding the draw method, calling my methods with the drawing inside init, and calling them from the cell. I get the print statements showing in the console, but no drawing on screen.
extension ChooseRouteViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Route", for: indexPath) as! PotentialRouteCell
cell.routeOutline = RouteOverview(frame: CGRect(x: 73 + 4, y: 8, width: (cell.bounds.width - 83), height: 98), route: instructions)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: possibleRouteCollectionView.bounds.width - 40, height: 150)
}
}
class RouteOverview: UIView {
init(frame: CGRect, route: [Instruction]) {
super.init(frame: frame)
getOutline(from: route)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private struct Overview {
let fromStation: Station
let toStation: Station
let lineName: String
init(from: Station, to: Station, line: String) {
self.fromStation = from
self.toStation = to
self.lineName = line
}
}
private var overview: [Overview] = []
private var keyStations: [String] = []
private var linesToDraw: Int = 0
private var linesDrawn: [CAShapeLayer] = []
private var lineX: CGFloat = 24.0
private var lineY: CGFloat {
return self.bounds.height / 2
}
private var lineLength: CGFloat {
return (self.bounds.width - 48) / CGFloat(overview.count)
}
private func getOutline(from route: [Instruction]) {
for instruction in route {
if instruction.type == .route {
let instructionOverview = Overview(from: instruction.route.first!.station, to: instruction.route.last!.station, line: instruction.line)
overview.append(instructionOverview)
}
}
linesToDraw = overview.count
print("\n Debug: There are \(linesToDraw) lines to draw. Each line is \(lineLength) points long.")
drawLine(fromPoint: CGPoint(x: lineX, y: lineY), toPoint: CGPoint(x: lineX + lineLength, y: lineY), lineName: overview[linesDrawn.count].lineName)
}
private func drawLine(fromPoint start: CGPoint, toPoint end: CGPoint, lineName: String) {
lineX += lineLength
let line = CAShapeLayer()
let path = UIBezierPath()
path.move(to: start)
path.addLine(to: end)
line.lineWidth = 8
line.lineCap = .round
line.strokeColor = UIColor(named: lineName)!.cgColor
line.fillColor = UIColor(named: lineName)!.cgColor
line.path = path.cgPath
self.layer.insertSublayer(line, at: 0)
linesDrawn.append(line)
linesToDraw -= 1
if linesToDraw >= 0 {
addDetail(at: end, lineName: lineName)
}
}
func addDetail(at point: CGPoint, lineName: String) {
if linesToDraw != 0 {
let circle = CAShapeLayer()
let path = UIBezierPath(arcCenter: point, radius: 8, startAngle: 0, endAngle: CGFloat(Double.pi * 2), clockwise: true)
circle.lineWidth = 6
circle.strokeColor = UIColor.black.cgColor
circle.fillColor = UIColor.black.cgColor
circle.path = path.cgPath
let innerCircle = CAShapeLayer()
let innerPath = UIBezierPath(arcCenter: point, radius: 4, startAngle: 0, endAngle: CGFloat(Double.pi * 2), clockwise: true)
innerCircle.lineWidth = 6
innerCircle.strokeColor = UIColor.white.cgColor
innerCircle.fillColor = UIColor.white.cgColor
innerCircle.path = innerPath.cgPath
self.layer.addSublayer(circle)
self.layer.insertSublayer(innerCircle, above: circle)
}
let lineNameLabel = RoundLabel(frame: CGRect(x: point.x - (lineLength / 2) - 18, y: point.y + 16, width: 40, height: 24))
lineNameLabel.cornerRadius = 5.0
lineNameLabel.text = String(lineName.prefix(3))
lineNameLabel.textAlignment = .center
lineNameLabel.font = UIFont(name: "London Tube", size: 15.0)
lineNameLabel.backgroundColor = UIColor(named: lineName)!
lineNameLabel.textColor = .white
lineNameLabel.clipsToBounds = true
self.addSubview(lineNameLabel)
self.setNeedsLayout()
self.setNeedsDisplay()
if linesToDraw >= 1 {
drawLine(fromPoint: CGPoint(x: point.x, y: lineY), toPoint: CGPoint(x: point.x + lineLength, y: lineY), lineName: overview[linesDrawn.count].lineName)
}
}
}
It should draw a line for each route instruction, in the color of the train line name. Where two lines meet, there should be a connector blob as seen on a London Underground tube map. There should also be an abbreviated train line name label the drawn line.
Upvotes: 0
Views: 632
Reputation: 437552
In cellForItemAt
you set routineOutline
to your RouteOverview
. So you're saving a reference to your custom view, but I don't see you adding the RouteOverview
to the view hierarchy at any point. (You're adding shape layers to RouteOverview
, but never adding the RouteOverview
, itself.) You need to call addSubview
at some point.
Upvotes: 1