如何在 iOS Swift4 中创建这个圆形?

Posted

技术标签:

【中文标题】如何在 iOS Swift4 中创建这个圆形?【英文标题】:How I can create this circular shape in iOS Swift4? 【发布时间】:2019-06-23 12:57:27 【问题描述】:

我必须在 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)

但我得到以下结果。

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

先谢谢大家了。

【问题讨论】:

您是否尝试过使较大圆圈的起始角度和结束角度与较小圆圈的位置相同? 【参考方案1】:

有很多方法可以实现这种效果,但一个简单的解决方案是不要将大圆绘制为单个圆弧,而是将其绘制为一系列圆弧,在小圆的边缘开始和停止。为此,您需要知道内圈的偏移量是多少。做一点三角函数,你可以计算出:

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 与小圆相比真的很宽,那么单独的大圆弧中的断点就不会与小圆的边缘很好地对齐。例如。假设小圆的半径为 22 点,但大圆弧的笔划比较宽,例如36 分。

如果你有这种情况(不是你的情况,而是为了未来的读者),另一种方法,正如 matt 建议的那样,将大弧绘制为一个笔划,然后使用路径将其遮盖小圆圈。

所以,想象一下你有:

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

UIBezierPath 的数组,称为 smallCirclePaths,用于所有小圆圈。

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

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

产生:

这是这个问题的一个稍微更通用的解决方案。

【讨论】:

【参考方案2】:

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

让我们将思维分为三层:

需要透出的背景

保持直线的层

小圆圈所在的层

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

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

回到直线层。给它一个面具。在小圆圈层的位置用透明圆圈构造该蒙版。

现在,面具在直线上“打了一个洞”——正好在圆圈覆盖它的地方。因此,我们似乎可以透过圆圈看到背景,因为在那个地方没有直线。

在现实生活中会有多个圆形层,蒙版会有多个透明圆形,直线是曲线,但一旦打孔完成,这就是一个小问题。

【讨论】:

如果您不知道如何使用口罩打孔,请参阅例如***.com/a/23452614/341994。

以上是关于如何在 iOS Swift4 中创建这个圆形?的主要内容,如果未能解决你的问题,请参考以下文章

在 ios sdk 中创建半圆形旋钮

如何在 Android 中创建圆形 ImageView? [复制]

如何在 Swift 中创建一个圆形按钮? [关闭]

如何在 Flutter 中创建圆形图标按钮?

如何在 Qt Designer 中创建圆形按钮

如何在CAD中创建圆形视口