繁体   English   中英

如何在iOS Swift4中创建此圆形?

[英]How I can create this circular shape in iOS Swift4?

我必须在UIView中创建如下图所示的形状。 但是我不知道如何绘制这种形状。 我试图使用带有CAShapeLayer的UIBezierPath路径成功绘制此形状,但圆线绘制成功,但是我无法绘制圆点和圆形填充颜色。 任何人都可以建议我如何使用任何库或UIBezierPath实现这种形状。

设计图

这是我正在尝试绘制此圆形的代码。

class ViewController: UIViewController {


var firstButton = UIButton()
var mylabel = UILabel()

override func viewDidLoad() {
    super.viewDidLoad()

    self.creatingLayerWithInformation()

}

func creatingLayerWithInformation(){
    let safeAreaHeight = self.view.safeAreaInsets.top
    let navBarHeight = self.navigationController?.navigationBar.frame.height

    self.addLayer(isClockWise: true, radius: self.view.frame.width * 0.72, xPoint: 0, yPoint: navBarHeight!, layerColor: UIColor.green, fillcolor: .clear)
    self.addLayer(isClockWise: true, radius: self.view.frame.width * 0.72, xPoint: self.view.frame.width, yPoint:  self.view.frame.height - 150, layerColor: UIColor.blue, fillcolor: .clear)

    let aa = self.view.frame.width * 0.72

    self.addLayer(isClockWise: true, radius: 10, xPoint: 0+aa, yPoint: navBarHeight!+5, layerColor: UIColor.blue, fillcolor: .clear)

    self.addLayer(isClockWise: true, radius: 10, xPoint: 0+15, yPoint: navBarHeight!+aa, layerColor: UIColor.blue, fillcolor: .clear)

}

func addLayer(isClockWise: Bool, radius: CGFloat, xPoint: CGFloat, yPoint: CGFloat, layerColor: UIColor, fillcolor: UIColor) {

    let pi = CGFloat(Float.pi)
    let start:CGFloat = 0.0
    let end :CGFloat = 20

    // circlecurve
    let path: UIBezierPath = UIBezierPath();
    path.addArc(
        withCenter: CGPoint(x:xPoint, y:yPoint),
        radius: (radius),
        startAngle: start,
        endAngle: end,
        clockwise: isClockWise
    )
    let layer = CAShapeLayer()
    layer.lineWidth = 3
    layer.fillColor = fillcolor.cgColor
    layer.strokeColor = layerColor.cgColor
    layer.path = path.cgPath
    self.view.layer.addSublayer(layer)
}}

但我得到以下结果。

在此处输入图片说明

请建议我如何实现这种形状。 如果我做错了什么,请纠正我。 如果有任何图书馆,也请提出建议。 请给我一些解决方案。

提前感谢大家。

有许多方法可以达到此效果,但是一个简单的解决方案是不将大圆画为单个弧,而是绘制为一系列在小圆的边缘开始和停止的弧。 为此,您需要知道与内圆的偏移量。 做一点三角法,可以将其计算为:

let angleOffset = asin(innerRadius / 2 / mainRadius) * 2

从而:

let path = UIBezierPath()
path.move(to: point(from: arcCenter, radius: mainRadius, angle: startAngle))

let anglePerChoice = (endAngle - startAngle) / CGFloat(choices.count)
let angleOffset = asin(innerRadius / 2 / mainRadius) * 2
var from = startAngle
for index in 0 ..< choices.count {
    var to = from + anglePerChoice / 2 - angleOffset
    path.addArc(withCenter: arcCenter, radius: mainRadius, startAngle: from, endAngle: to, clockwise: true)
    to = from + anglePerChoice
    from += anglePerChoice / 2 + angleOffset
    path.move(to: point(from: arcCenter, radius: mainRadius, angle: from))
    path.addArc(withCenter: arcCenter, radius: mainRadius, startAngle: from, endAngle: to, clockwise: true)

    from = to
}

let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = strokeColor.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = lineWidth
layer.addSublayer(shapeLayer)

哪里:

func point(from point: CGPoint, radius: CGFloat, angle: CGFloat) -> CGPoint {
    return CGPoint(x: point.x + radius * cos(angle),
                   y: point.y + radius * sin(angle))
}

产生:

在此处输入图片说明

因此,当您添加内圆时:

在此处输入图片说明


尽管上面很简单,但是它有局限性。 特别是,如果大弧线的lineWidth与小圆弧的lineWidth相比确实很宽,则单独的大弧线的折线将无法与小圆弧的边缘很好地对齐。 例如,想象小圆弧半径为22点,但是大圆弧的笔划相对较宽,例如36点。

在此处输入图片说明

如果您有这种情况(不是您的情况,而是为了将来的读者使用),如暗淡所建议的,另一种方法是将大圆弧绘制为单个笔触,然后使用小圆圈的路径对其进行遮罩。

因此,假设您有:

  • 单个CAShapeLayer ,称为mainArcLayer ,用于大弧;

  • 所有小圆圈的UIBezierPath数组,称为smallCirclePaths

然后,您可以在UIView子类的layoutSubviews (或UIViewController子类中的viewDidLayoutSubviews中创建掩码,如下所示:

override func layoutSubviews() {
    super.layoutSubviews()

    let path = UIBezierPath(rect: bounds)
    smallCirclePaths.forEach { path.append($0) }

    let mask = CAShapeLayer()
    mask.fillColor = UIColor.white.cgColor
    mask.strokeColor = UIColor.clear.cgColor
    mask.lineWidth = 0
    mask.path = path.cgPath
    mask.fillRule = .evenOdd

    mainArcLayer.mask = mask
}

产生:

在此处输入图片说明

这是对该问题的稍微更笼统的解决方案。

以最简单的方式考虑问题。 想象一条直线,中间有一个小圆圈。

让我们将思维分为三层:

  • 需要显示的背景

  • 保持直线的层

  • 包含小圆圈的图层

计算小圆圈层相对于直线层的位置。

将小圆圈图层放置在该位置。 好的,但是直线会显示出来。

返回直线层。 给它戴上口罩 在小圆圈层的确切位置用透明圆圈构造该蒙版。

现在,遮罩沿着直线“打孔” —恰好是圆圈覆盖的位置。 因此,我们似乎可以从圆环中看到背景,因为直线恰好在那个位置丢失了。

在现实生活中,将有多个圆形图层,并且蒙版将具有多个透明圆形,并且直线将是一条曲线,但是一旦您完成了打孔操作,这将是一个小问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM