首页 > 解决方案 > CAShapeLayer 未显示在屏幕上

问题描述

UICollectionViewCell有一个里面有一个 UIView 的。将单元格出列时,我使用必要的数据对其进行初始化。初始化数据后,在 内部UIView,有一些要显示的图形。然而,什么也没有出现。

最初,这都是在UICollectionView cellForItemAt方法内部并画线,但它应该在 UIView 内部,所以我将它子类化并将代码放在那里。这是它停止工作的地方。

我尝试过覆盖 draw 方法,使用 init 内部的绘图调用我的方法,然后从单元格中调用它们。我得到控制台中显示的打印语句,但屏幕上没有绘图。

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)
        }
    }
}

它应该为每条路线指令画一条线,以火车线路名称的颜色。在两条线相交的地方,应该有一个连接器斑点,如伦敦地铁地图上所示。绘制的线还应该有一个缩写的火车线名称标签。

标签: iosswiftuibezierpath

解决方案


cellForItemAt你设置routineOutline为你的RouteOverview. 因此,您正在保存对自定义视图的引用,但我看不到您RouteOverview在任何时候都将其添加到视图层次结构中。(您正在向 中添加形状图层RouteOverview,但从不添加RouteOverview本身。)您需要addSubview在某个时候调用。


推荐阅读