You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用UIBezierPath绘制交替虚线与点线?现有代码仅显示点

解决UIBezierPath交替虚线和点线的绘制问题

你的代码里有两个关键错误导致只能渲染出点线:

  • UIBezierPath的lineCapStyle是全局属性,循环里反复赋值只会保留最后一次的设置(你的循环最后i=10是偶数,最终生效的是round线帽),根本没法给路径的不同段落单独设置样式。
  • 当前的lineDash数组[0.001, path.lineWidth * 2]配合round线帽,本质就是画连续的圆点——0长度的线段加上圆形线帽,会生成直径等于线宽的圆点,间隔是线宽的2倍。

下面给出两种可行的实现方式:

方式一:逐段切换样式绘制(Core Graphics)

通过Core Graphics逐段绘制,每段切换线帽和虚线模式,精准控制交替效果:

func drawAlternatingDashesAndDots() {
    let lineWidth: CGFloat = 8
    let startX: CGFloat = 10
    let endX: CGFloat = 290
    let dashLength: CGFloat = lineWidth * 3 // 长划线长度
    let segmentGap: CGFloat = lineWidth * 2 // 长划线和圆点的间隔
    let dotGap: CGFloat = lineWidth * 2 // 圆点之间的间隔

    UIGraphicsBeginImageContextWithOptions(CGSize(width:300, height:20), false, 2)
    defer { UIGraphicsEndImageContext() }
    
    let context = UIGraphicsGetCurrentContext()!
    UIColor.white.setFill()
    context.fill(.infinite)
    UIColor.black.setStroke()
    context.setLineWidth(lineWidth)

    var currentX = startX
    while currentX < endX {
        // 绘制长划线(方形线帽)
        context.setLineCap(.square)
        context.setLineDash(phase: 0, lengths: [dashLength, segmentGap])
        context.move(to: CGPoint(x: currentX, y: 10))
        let dashEnd = min(currentX + dashLength, endX)
        context.addLine(to: CGPoint(x: dashEnd, y: 10))
        context.strokePath()
        currentX = dashEnd + segmentGap

        guard currentX < endX else { break }

        // 绘制圆点(圆形线帽,用0长度线段实现)
        context.setLineCap(.round)
        context.setLineDash(phase: 0, lengths: [0, dotGap])
        context.move(to: CGPoint(x: currentX, y: 10))
        context.addLine(to: CGPoint(x: currentX, y: 10)) // 0长度线段
        context.strokePath()
        currentX += dotGap
    }

    if let image = UIGraphicsGetImageFromCurrentImageContext() {
        dashDotDashLineView.image = image
    }
}

方式二:双路径叠加(UIBezierPath)

创建两个独立的UIBezierPath,分别绘制长划线和圆点,通过偏移起点实现交替效果,代码更简洁:

func drawAlternatingDashesAndDots() {
    let lineWidth: CGFloat = 8
    let startX: CGFloat = 10
    let endX: CGFloat = 290
    let dashLength: CGFloat = lineWidth * 3
    let gap: CGFloat = lineWidth * 2
    let totalCycleLength = dashLength + gap + gap // 长划线+间隔+圆点间隔的总周期

    UIGraphicsBeginImageContextWithOptions(CGSize(width:300, height:20), false, 2)
    defer { UIGraphicsEndImageContext() }
    
    UIColor.white.setFill()
    UIGraphicsGetCurrentContext()!.fill(.infinite)
    UIColor.black.setStroke()

    // 绘制长划线路径
    let dashPath = UIBezierPath()
    dashPath.move(to: CGPoint(x: startX, y: 10))
    dashPath.addLine(to: CGPoint(x: endX, y: 10))
    dashPath.lineWidth = lineWidth
    dashPath.lineCapStyle = .square
    dashPath.setLineDash([dashLength, totalCycleLength], count: 2, phase: 0)
    dashPath.stroke()

    // 绘制圆点路径
    let dotPath = UIBezierPath()
    dotPath.move(to: CGPoint(x: startX + dashLength + gap, y: 10))
    dotPath.addLine(to: CGPoint(x: endX, y: 10))
    dotPath.lineWidth = lineWidth
    dotPath.lineCapStyle = .round
    dotPath.setLineDash([0, totalCycleLength], count: 2, phase: 0)
    dotPath.stroke()

    if let image = UIGraphicsGetImageFromCurrentImageContext() {
        dashDotDashLineView.image = image
    }
}

内容的提问来源于stack exchange,提问作者narner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 20:40:31