在 Tableview 中使用 BezierPath 创建时间线视图

Posted

技术标签:

【中文标题】在 Tableview 中使用 BezierPath 创建时间线视图【英文标题】:Create a Timeline View using BezierPath in Tableview 【发布时间】:2016-11-10 11:08:48 【问题描述】:

我正在尝试在 TableView 中绘制一个包含 5 行的里程碑,我在单元格中添加了一个标签为“O”,这里的行高是 44,我正在尝试连接这些点 像这样的东西 O--------O--------O-----O-----O 垂直方向,但我无法弄清楚这里缺少什么,请参考以下代码

 class StopslistTableViewCell:UITableViewCell

@IBOutlet weak var milestoneLbl: UILabel!

override func draw(_ rect: CGRect) 

    let scrrenX = UIScreen.main.bounds.width - 30

    let frametosuperview = milestoneLbl.convert(milestoneLbl!.frame, to: self.superview)

    print("dotframetosuperview",frametosuperview)

    //print(CGPoint(x: scrrenX, y: previousposY + rect.size.height))

    //frametosuperview.origin.y > 40 ? frametosuperview.origin.y - 20 : frametosuperview.origin.y

    let path = UIBezierPath()
    path.move(to: CGPoint(x: scrrenX, y:frametosuperview.origin.y < 30 ? frametosuperview.origin.y : frametosuperview.origin.y - frametosuperview.height))

    print("move to point--->",frametosuperview.origin.y < 30 ? frametosuperview.origin.y : frametosuperview.origin.y - frametosuperview.height)

    path.addLine(to: CGPoint(x: scrrenX, y: frametosuperview.origin.y < 30 ? frametosuperview.height + 24 : (frametosuperview.origin.y + 24)))
    print("add line to point--->",CGPoint(x: scrrenX, y: frametosuperview.origin.y < 30 ? frametosuperview.height + 24 : (frametosuperview.origin.y + 24)))

    path.lineWidth = 5

    UIColor.red.setStroke()
    path.stroke()

    setNeedsDisplay()

调试输出

dotframetosuperview (560.0, 20.0, 20.0, 20.0) 
move to point---> 20.0
add line to point---> (290.0, 44.0)
dotframetosuperview (560.0, 64.0, 20.0, 20.0)
move to point---> 44.0
add line to point---> (290.0, 88.0)
dotframetosuperview (560.0, 108.0, 20.0, 20.0)
move to point---> 88.0
add line to point---> (290.0, 132.0)
dotframetosuperview (560.0, 152.0, 20.0, 20.0)
move to point---> 132.0
add line to point---> (290.0, 176.0)
dotframetosuperview (560.0, 196.0, 20.0, 20.0)
move to point---> 176.0
add line to point---> (290.0, 220.0)

我需要这样的东西

我无法得到想要的结果,我在这里遗漏了什么吗..?

【问题讨论】:

请发布更多信息。 “我无法获得预期的结果”是什么问题?预期输出,实际输出... 如果您想了解更多信息,请复制 tableviewcell 中的代码,在 xib 中获取 tableview,拖动单元格,在其上放置标签,将标签附加到里程碑并运行。 【参考方案1】:

您不需要创建UILabel。而是创建一个圆圈和一条带有虚线图案的线:

let offSet:CGFloat = 20.0
let circleRadius:CGFloat = 5.0

override func draw(_ rect: CGRect) 

    //creating a circle
    let circlePath = UIBezierPath(arcCenter: CGPoint(x: offSet,y: circleRadius), radius: CGFloat(circleRadius), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = circlePath.cgPath
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.strokeColor = UIColor.black.cgColor
    shapeLayer.lineWidth = 2.0
    circlePath.stroke()

    //creating a line with dashed pattern
    let  dashPath = UIBezierPath()
    let  startPoint = CGPoint(x:offSet  ,y:circleRadius * 2)
    dashPath.move(to: startPoint)

    let  endPoint = CGPoint(x:offSet,y:
        self.bounds.maxY)
    dashPath.addLine(to: endPoint)

    let  dashes: [ CGFloat ] = [4, 1] //line with dash pattern of 4 thick and i unit space
    dashPath.setLineDash(dashes, count: dashes.count, phase: 0)
    dashPath.lineWidth = 2.0
    dashPath.lineCapStyle = .butt
    UIColor.black.set()
    dashPath.stroke()


输出:

编辑:因为 OP 希望时间线圆圈从单元格的中心出现。

var allRows = Int()
var currentIndexPath = IndexPath()
let offSet:CGFloat = 20.0
let circleRadius:CGFloat = 5.0


override func draw(_ rect: CGRect) 

    //creating a circle
    let circlePath = UIBezierPath(arcCenter: CGPoint(x: offSet,y: self.bounds.midY), radius: CGFloat(circleRadius), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = circlePath.cgPath
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.strokeColor = UIColor.black.cgColor
    shapeLayer.lineWidth = 2.0
    circlePath.stroke()

    //creating a line with dashed pattern
    let  dashPath = UIBezierPath()
    var startPoint = CGPoint()

    if currentIndexPath.row  == 0

        startPoint = CGPoint(x:offSet  ,y:self.bounds.midY)
    else

        startPoint = CGPoint(x:offSet  ,y:0)
    
    dashPath.move(to: startPoint)

    var endPoint = CGPoint()

    if currentIndexPath.row == allRows-1

        endPoint = CGPoint(x:offSet,y:
            self.bounds.midY)
    else

        endPoint = CGPoint(x:offSet,y:
            self.bounds.maxY)

    
    dashPath.addLine(to: endPoint)

    let  dashes: [ CGFloat ] = [4, 1] //line with dash pattern of 4 thick and i unit space
    dashPath.setLineDash(dashes, count: dashes.count, phase: 0)
    dashPath.lineWidth = 2.0
    dashPath.lineCapStyle = .butt
    UIColor.black.set()
    dashPath.stroke()

你的cellForRowAt indexPath应该配置为

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

        .......
        cell.allRows = totalNumberOfRows
        cell.currentIndexPath = indexPath
        return cell


    

这会导致以下 O/P:

【讨论】:

它确实回答了这个问题,但我对这个问题的意图是,“为什么这段代码没有像我预期的那样绘制,因为 x,y 线似乎是正确的”,我也使用了标签这样我就不必在每次移动里程碑的位置时重新设置圆的框架 @iSwift 您正在构建的解决方案只是一个 hack 放置一个圆形 UILabel 和一条虚线..所以,我想我会以正确的方式发布一个更好的答案。 假设我想把圆圈放在中间,但线的起点应该是从第一个圆圈中心到末端圆圈中心 @iSwift 请说清楚..可能是截图..最好发布一个新问题。 请自行尝试,如果没有我会在有空时编辑。

以上是关于在 Tableview 中使用 BezierPath 创建时间线视图的主要内容,如果未能解决你的问题,请参考以下文章

iOS 实现点击在tableview中使用3D Touch

如何使用此代码在 tableview 中使用搜索栏?

如何在 RxSwift 中使用 tableView 数据源(numberOfRowsInSection)?

在 Swift 中使用数组创建 TableView

如何在 UIViewController 中使用 TableView?

如何在iOS swift的tableview中使用json响应中的键和值?