【问题标题】:Swift/UIView Draw something like tachometerSwift/UIView 绘制转速表之类的东西
【发布时间】:2018-04-10 12:51:47
【问题描述】:

我想我有点停电了,但我不能简单地在 Swift 中使用 BezierPaths。想要我想做的就像在屏幕截图上一样:

所以它就像一个具有三种颜色的转速表:

我所拥有的如下:

diagram.layer.borderWidth = 4.0
    diagram.layer.borderColor = UIColor.black.cgColor

    let pi = CGFloat(Float.pi)
    let start:CGFloat = 0.0
    let end :CGFloat = pi
    let radius : CGFloat = diagram.frame.width/3
    let middle = CGPoint(x: diagram.frame.size.width/2, y:diagram.frame.size.height/2)

    let path: UIBezierPath = UIBezierPath();
    path.addArc(
        withCenter: CGPoint(x: middle.x, y: middle.y),
        radius: radius,
        startAngle: start,
        endAngle: end,
        clockwise: false
    )

    let layer = CAShapeLayer()
    layer.fillColor = UIColor.clear.cgColor
    layer.strokeColor = UIColor.red.cgColor
    layer.path = path.cgPath
    diagram.layer.addSublayer(layer)

这只是第一个弧,但它让我抓狂。它没有居中,这很奇怪,因为我使用的是 Uiview 的大小。我的 UIView 显然被称为“图表”。

有没有人有一个很好的 Swift 示例如何在屏幕截图中执行类似的操作? 感谢阅读!

======= 这只是与andykkt的答案有关的代码

func drawCompareGauge(frame: CGRect = CGRect(x: 0, y: 0, width: 180, height: 92), leftPercentage: CGFloat = 0.5) {
    //// General Declarations
    let context = UIGraphicsGetCurrentContext()

    //// Color Declarations
    let leftColor = UIColor(red: 0.278, green: 0.757, blue: 0.749, alpha: 1.000)
    let rightColor = UIColor(red: 0.557, green: 0.400, blue: 0.867, alpha: 1.000)

    //// Variable Declarations
    let leftDashed: CGFloat = 247 * leftPercentage

    //// rightRing Drawing
    let rightRingPath = UIBezierPath()
    rightRingPath.move(to: CGPoint(x: frame.minX + 11.5, y: frame.minY + 91.5))
    rightRingPath.addCurve(to: CGPoint(x: frame.minX + 42.73, y: frame.minY + 28.82), controlPoint1: CGPoint(x: frame.minX + 11.5, y: frame.minY + 65.89), controlPoint2: CGPoint(x: frame.minX + 23.76, y: frame.minY + 43.15))
    rightRingPath.addCurve(to: CGPoint(x: frame.minX + 90, y: frame.minY + 13), controlPoint1: CGPoint(x: frame.minX + 55.88, y: frame.minY + 18.89), controlPoint2: CGPoint(x: frame.minX + 72.25, y: frame.minY + 13))
    rightRingPath.addCurve(to: CGPoint(x: frame.minX + 168.5, y: frame.minY + 91.5), controlPoint1: CGPoint(x: frame.minX + 133.35, y: frame.minY + 13), controlPoint2: CGPoint(x: frame.minX + 168.5, y: frame.minY + 48.15))
    rightColor.setStroke()
    rightRingPath.lineWidth = 23
    context?.saveGState()
    //CGContextSetLineDash(context, 0, [247, 247], 2)
    //context!.setLineDash(phase: <#T##CGFloat#>, lengths: <#T##[CGFloat]#>)
    context?.setLineDash(phase: 0, lengths: [247,247])
    //problem
    rightRingPath.stroke()
    context?.restoreGState()


    //// leftRing Drawing
    let leftRingPath = UIBezierPath()
    leftRingPath.move(to: CGPoint(x: frame.minX + 11.5, y: frame.minY + 91.5))
    leftRingPath.addCurve(to: CGPoint(x: frame.minX + 42.73, y: frame.minY + 28.82), controlPoint1: CGPoint(x: frame.minX + 11.5, y: frame.minY + 65.89), controlPoint2: CGPoint(x: frame.minX + 23.76, y: frame.minY + 43.15))
    leftRingPath.addCurve(to: CGPoint(x: frame.minX + 90, y: frame.minY + 13), controlPoint1: CGPoint(x: frame.minX + 55.88, y: frame.minY + 18.89), controlPoint2: CGPoint(x: frame.minX + 72.25, y: frame.minY + 13))
    leftRingPath.addCurve(to: CGPoint(x: frame.minX + 168.5, y: frame.minY + 91.5), controlPoint1: CGPoint(x: frame.minX + 133.35, y: frame.minY + 13), controlPoint2: CGPoint(x: frame.minX + 168.5, y: frame.minY + 48.15))
    leftColor.setStroke()
    leftRingPath.lineWidth = 23
    context?.saveGState()
    //context!.setLineDash(context, 0, [leftDashed, 247], 2)
    //Problem
    context?.setLineDash(phase: 0, lengths: [leftDashed,247])
    leftRingPath.stroke()
    context?.restoreGState()


    //// Text Drawing
    let textRect = CGRect(x: frame.minX + 7, y: frame.minY + 74, width: 11, height: 21)
    let textTextContent = NSString(string: "L")
    let textStyle = NSMutableParagraphStyle()
    textStyle.alignment = .left

    let textFontAttributes = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: UIFont.systemFontSize), NSAttributedStringKey.foregroundColor: UIColor.white, NSAttributedStringKey.paragraphStyle: textStyle]

    let textTextHeight: CGFloat = textTextContent.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).size.height
    context?.saveGState()
    context?.clip(to: textRect)
    textTextContent.draw(in: CGRect(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight) / 2, width: textRect.width, height: textTextHeight), withAttributes: textFontAttributes)
    context?.restoreGState()


    //// Text 2 Drawing
    let text2Rect = CGRect(x: frame.minX + 164, y: frame.minY + 76, width: 11, height: 17)
    let text2TextContent = NSString(string: "R")
    let text2Style = NSMutableParagraphStyle()
    text2Style.alignment = .left

    let text2FontAttributes = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: UIFont.systemFontSize), NSAttributedStringKey.foregroundColor: UIColor.white, NSAttributedStringKey.paragraphStyle: text2Style]

    let text2TextHeight: CGFloat = text2TextContent.boundingRect(with: CGSize(width: text2Rect.width, height: CGFloat.infinity), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: text2FontAttributes, context: nil).size.height
    context?.saveGState()
    context?.clip(to: text2Rect)
    //CGContextClipToRect(context!, text2Rect)
    text2TextContent.draw(in: CGRect(x: text2Rect.minX, y: text2Rect.minY + (text2Rect.height - text2TextHeight) / 2, width: text2Rect.width, height: text2TextHeight), withAttributes: text2FontAttributes)
    context?.restoreGState()
}

【问题讨论】:

  • 与您的问题无关,但为什么不简单地 withCenter: middle 和 CGFloat.pi
  • 你说得对,我本来可以那样做的。谢谢:)
  • 顺便说一句,您可以使用视图中心属性diagram.center。 path.addArc(withCenter: diagram.center, radius: diagram.frame.width / 4, startAngle: 0, endAngle: .pi, clockwise: false)
  • 您应该使用bounds,而不是frame。视图的绘制不应根据视图在其父视图中的放置位置而改变。
  • 其中一个选项是使用“PaintCode”之类的工具,您可以绘制和导出代码。

标签: swift uiview draw


【解决方案1】:

我以“PaintCode”为例画出来,你可以用paintcode画出你想要的样子。

@IBDesignable class GaugeView: UIView {

@IBInspectable var leftPercentage: CGFloat = 0.708 {
    didSet {
        setNeedsDisplay()
    }
}

@IBInspectable var otherPercentage: CGFloat = 0.206 {
    didSet {
        setNeedsDisplay()
    }
}

override func draw(_ rect: CGRect) {
    // Drawing code
    drawCompareGauge(frame: bounds, leftPercentage: leftPercentage, otherPercentage: otherPercentage)
}

func drawCompareGauge(frame: CGRect = CGRect(x: 0, y: 0, width: 180, height: 92), leftPercentage: CGFloat = 0.708, otherPercentage: CGFloat = 0.206) {
    //// General Declarations
    guard let context = UIGraphicsGetCurrentContext() else { return }

    //// Color Declarations
    let leftColor = UIColor(red: 0.278, green: 0.757, blue: 0.749, alpha: 1.000)
    let rightColor = UIColor(red: 0.557, green: 0.400, blue: 0.867, alpha: 1.000)
    let otherColor = UIColor(red: 0.800, green: 0.320, blue: 0.320, alpha: 1.000)

    //// Variable Declarations
    let leftDashed: CGFloat = 247 * leftPercentage
    let otherDashed: CGFloat = 247 * otherPercentage

    //// rightRing Drawing
    let rightRingPath = UIBezierPath()
    rightRingPath.move(to: CGPoint(x: frame.minX + 11.5, y: frame.minY + 91.5))
    rightRingPath.addCurve(to: CGPoint(x: frame.minX + 42.73, y: frame.minY + 28.82), controlPoint1: CGPoint(x: frame.minX + 11.5, y: frame.minY + 65.89), controlPoint2: CGPoint(x: frame.minX + 23.76, y: frame.minY + 43.15))
    rightRingPath.addCurve(to: CGPoint(x: frame.minX + 90, y: frame.minY + 13), controlPoint1: CGPoint(x: frame.minX + 55.88, y: frame.minY + 18.89), controlPoint2: CGPoint(x: frame.minX + 72.25, y: frame.minY + 13))
    rightRingPath.addCurve(to: CGPoint(x: frame.minX + 168.5, y: frame.minY + 91.5), controlPoint1: CGPoint(x: frame.minX + 133.35, y: frame.minY + 13), controlPoint2: CGPoint(x: frame.minX + 168.5, y: frame.minY + 48.15))
    rightColor.setStroke()
    rightRingPath.lineWidth = 23
    context.saveGState()
    context.setLineDash(phase: 0, lengths: [247, 247])
    rightRingPath.stroke()
    context.restoreGState()


    //// leftRing Drawing
    let leftRingPath = UIBezierPath()
    leftRingPath.move(to: CGPoint(x: frame.minX + 11.5, y: frame.minY + 91.5))
    leftRingPath.addCurve(to: CGPoint(x: frame.minX + 42.73, y: frame.minY + 28.82), controlPoint1: CGPoint(x: frame.minX + 11.5, y: frame.minY + 65.89), controlPoint2: CGPoint(x: frame.minX + 23.76, y: frame.minY + 43.15))
    leftRingPath.addCurve(to: CGPoint(x: frame.minX + 90, y: frame.minY + 13), controlPoint1: CGPoint(x: frame.minX + 55.88, y: frame.minY + 18.89), controlPoint2: CGPoint(x: frame.minX + 72.25, y: frame.minY + 13))
    leftRingPath.addCurve(to: CGPoint(x: frame.minX + 168.5, y: frame.minY + 91.5), controlPoint1: CGPoint(x: frame.minX + 133.35, y: frame.minY + 13), controlPoint2: CGPoint(x: frame.minX + 168.5, y: frame.minY + 48.15))
    leftColor.setStroke()
    leftRingPath.lineWidth = 23
    context.saveGState()
    context.setLineDash(phase: 0, lengths: [leftDashed, 247])
    leftRingPath.stroke()
    context.restoreGState()


    //// leftRing 2 Drawing
    let leftRing2Path = UIBezierPath()
    leftRing2Path.move(to: CGPoint(x: frame.minX + 11.5, y: frame.minY + 91.5))
    leftRing2Path.addCurve(to: CGPoint(x: frame.minX + 42.73, y: frame.minY + 28.82), controlPoint1: CGPoint(x: frame.minX + 11.5, y: frame.minY + 65.89), controlPoint2: CGPoint(x: frame.minX + 23.76, y: frame.minY + 43.15))
    leftRing2Path.addCurve(to: CGPoint(x: frame.minX + 90, y: frame.minY + 13), controlPoint1: CGPoint(x: frame.minX + 55.88, y: frame.minY + 18.89), controlPoint2: CGPoint(x: frame.minX + 72.25, y: frame.minY + 13))
    leftRing2Path.addCurve(to: CGPoint(x: frame.minX + 168.5, y: frame.minY + 91.5), controlPoint1: CGPoint(x: frame.minX + 133.35, y: frame.minY + 13), controlPoint2: CGPoint(x: frame.minX + 168.5, y: frame.minY + 48.15))
    otherColor.setStroke()
    leftRing2Path.lineWidth = 23
    context.saveGState()
    context.setLineDash(phase: 0, lengths: [otherDashed, 247])
    leftRing2Path.stroke()
    context.restoreGState()
}

我已将代码更改为 class 并支持最新的 xcode 和 swift。您可以在视图控制器上放置一个 this 视图来查看结果并更改 leftPercentage animate gauge。

================================

我已经更新了代码以显示 3 个不同的值作为仪表,希望这可以帮助您弄清楚。请参阅下面的 gif 以了解此控件的实际操作。

【讨论】:

  • 您好,谢谢您的回答!我花了一段时间来看看你的代码。不幸的是,我使用的是 Swift 4,所以已经进行了数百次更改/重构,但现在我确信我已经重构了所有内容。我将我的新代码发布到主题中。不幸的是,它只是空白。我用错了吗?
  • 我只是想看看结果,然后才能开始理解代码本身。
  • 我正在使用函数本身,就像您在示例中使用 drawCompareGauge(frame: CGRect(x: 0, y: 0, width: 180, height: 92), leftPercentage: 0.5) 所做的那样跨度>
  • @FranzFerdinand 抱歉,我拥有的 Paintcode 版本不支持最新的 Swift 代码。我已经解决了这个问题。
  • 嘿,我现在有时间检查代码。我确实理解了关于文本的部分(L 和 R),但我需要帮助来理解绘图部分。您确实为左右曲线使用了完全相同的点,但最终,它实现了我想要做的。这是如何运作的?以及 setLineDash 的用途。我试图理解它,而不是让它具有响应性、居中和三种颜色。
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 2017-01-28
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多