如何在 swift 中自定义 CAShapeLayer

问题描述 投票:0回答:1

我有一个自定义视图,我用它来使用 CAShapeLayer 创建形状。这是当前输出。

我想要实现的是:

图中突出显示的白色圆圈

这是我用来创建弧形的代码

let gaugeLayer = CAShapeLayer()

  if bgLayer == nil {
      bgLayer = CAShapeLayer.getOval(lineWidth, strokeStart: 0, strokeEnd: 0.75, strokeColor: _bgStartColor, fillColor: UIColor.clear, shadowRadius: shadowRadius, shadowOpacity: shadowOpacity, shadowOffsset: CGSize.zero, bounds: bounds)
      bgLayer.frame = layer.bounds
      gaugeLayer.addSublayer(bgLayer)
  }

  if ringLayer == nil {
      ringLayer = CAShapeLayer.getOval(lineWidth, strokeStart: 0, strokeEnd: 0.75, strokeColor: UIColor.clear, fillColor: UIColor.clear, shadowRadius: shadowRadius, shadowOpacity: shadowOpacity, shadowOffsset: CGSize.zero, bounds: bounds)

      ringLayer.frame = layer.bounds
      gaugeLayer.addSublayer(ringLayer)
  }
  //...
  ringLayer.lineCap = .round
  bgLayer.lineCap = .round
  return gaugeLayer

getOval:

func getOval(_ lineWidth: CGFloat,
             strokeStart: CGFloat,
               strokeEnd: CGFloat,
             strokeColor: UIColor,
               fillColor: UIColor,
            shadowRadius: CGFloat,
           shadowOpacity: Float,
           shadowOffsset: CGSize,
                  bounds: CGRect,
             rotateAngle: Double? = nil,
             anchorPoint: CGPoint? = nil,) -> CAShapeLayer {

    var arc = CAShapeLayer()
    let rect = bounds.insetBy(dx: CGFloat(lineWidth / 2.0), dy: CGFloat(lineWidth / 2.0))
    let arcDiameter: CGFloat = min(bounds.width, bounds.height) - lineWidth
    let X = bounds.midX
    let Y = bounds.midY
    arc.path = UIBezierPath(ovalIn: CGRect(x: (X - (arcDiameter / 2)), y: (Y - (arcDiameter / 2)), width: arcDiameter, height: arcDiameter)).cgPath

    ////

    arc.lineWidth = lineWidth

    arc.strokeStart = strokeStart

    arc.strokeColor = strokeColor.cgColor
    arc.fillColor = fillColor.cgColor
    arc.shadowColor = UIColor.black.cgColor
    arc.shadowRadius = shadowRadius
    arc.shadowOpacity = shadowOpacity
    arc.shadowOffset = shadowOffsset

    if let anchorPoint = anchorPoint {
        arc.anchorPoint = anchorPoint
    }
    if let rotateAngle = rotateAngle {
        arc.transform = CATransform3DRotate(arc.transform, CGFloat(rotateAngle), 0, 0, 1)
    }

    arc.strokeEnd = strokeEnd


    ////
    return arc
}

白色圆圈不是静止的,它可以沿着弧线移动(因为它是蓝色进度条的尖端)。我知道如何创建圆形,但我不确定如何从这里开始。我怎样才能做到这一点?

编辑:

根据评论,我添加了白点,但位置不正确。我的计算有误吗?

lazy var currentPositionDotLayer: CALayer = {
    let layer = CALayer()
    layer.backgroundColor = UIColor.white.cgColor
    let rect = CGRect(x: 0, y: 0, width: lineWidth, height: lineWidth)
    layer.frame = rect

    let gradientLayer = CAGradientLayer()
    gradientLayer.colors = [UIColor.white.cgColor, UIColor.clear.cgColor]
    gradientLayer.type = .radial
    gradientLayer.frame = rect
    gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 1, y: 1)
    gradientLayer.locations = [0.5, 1]

    layer.mask = gradientLayer

    return layer
}()

open override func layoutSubviews() {
    ...
    layer.addSublayer(currentPositionDotLayer)
    updatePaths()
    ...
}

func updatePaths() {
    let rect = bounds.insetBy(dx: lineWidth / 2, dy: lineWidth / 2)
    
    let halfWidth = rect.width / 2
    let height = rect.height
    let theta = atan(halfWidth / height)
    
    let radius = (min(bounds.width, bounds.height) - lineWidth) / 2
    let center = CGPoint(x: rect.midX, y: rect.minY + radius)
    let delta = (Double.pi / 2 - theta) * 2
    let startAngle = Double.pi * 3 / 2 - delta
    let endAngle = .pi * 3 / 2 + delta

    let currentAngle = (endAngle - startAngle) * (rate / maxValue) + startAngle
    let dotCenter = CGPoint(x: center.x + radius * cos(currentAngle),
                            y: center.y + radius * sin(currentAngle))
    currentPositionDotLayer.position = dotCenter
}

ios swift calayer cashapelayer
1个回答
0
投票

CAShapeLayer 用一种颜色绘制整个形状。

您需要为弧形创建两个自定义形状,一端凸出,另一端凹入,或者浅蓝色弧形、深蓝色弧形和白色圆圈。使用 2 个带圆端的法线弧和一个圆会更简单,因为它会使用现有的形状。

如果你把白色圆圈放在其他两个上面并正确放置它们,它会给出你想要的结果。

© www.soinside.com 2019 - 2024. All rights reserved.