如何使用CALayer创建一个圆形?

16

我已经测试了下面的代码,但是当我给它添加限制条件时,它变成了一个小小的圆圈:

 override func drawRect(rect: CGRect) {
var path = UIBezierPath(ovalInRect: rect)
fillColor.setFill()
path.fill()

//set up the width and height variables
//for the horizontal stroke
let plusHeight:CGFloat = 300.0
let plusWidth:CGFloat = 450.0

//create the path
var plusPath = UIBezierPath()

//set the path's line width to the height of the stroke
plusPath.lineWidth = plusHeight

//move the initial point of the path
//to the start of the horizontal stroke
plusPath.moveToPoint(CGPoint(
  x:self.bounds.width/2 - plusWidth/2 + 0.5,
  y:self.bounds.height/2 + 0.5))

//add a point to the path at the end of the stroke
plusPath.addLineToPoint(CGPoint(
  x:self.bounds.width/2 + plusWidth/2 + 0.5,
  y:self.bounds.height/2 + 0.5))

}

尝试将其放置于viewDidAppear中。 - Leo Dabus
3个回答

19

随意更改半径和填充颜色。 :)

import Foundation
import UIKit

class CircleLayerView: UIView {
    var circleLayer: CAShapeLayer!

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        if circleLayer == nil {
            circleLayer = CAShapeLayer()
            let radius: CGFloat = 150.0
            circleLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 2.0 * radius, height: 2.0 * radius), cornerRadius: radius).cgPath
            circleLayer.position = CGPoint(x: self.frame.midX - radius, y: self.frame.midY - radius)
            circleLayer.fillColor = UIColor.blue.cgColor
            self.layer.addSublayer(circleLayer)
        }
    }
}

1
有点挑剔,但是在您子类化UIView的情况下没有必要调用super:https://dev59.com/questions/Fl8d5IYBdhLWcg3wv0Yg#26479578 - thattyson
此外,为了避免将circleLayer作为隐式解包可选项(CAShapeLayer!),您可以实例化let circleLayer = CAShapeLayer()并使用guard circleLayer.superlayer == nil else { return }来防止它具有超级图层。在drawRect中。 - thattyson
1
我忘记了是哪个WWDC会议,但苹果曾表示你不应该在drawRect中添加图层。这很有道理。相反,在视图的布局完成后设置图层,配置它们,然后让渲染系统自动处理它们。 - Womble
1
这个答案完全错误。 - Fattie

15

传递到drawRect中的rect是需要更新的区域,而不是绘图的大小。在你的情况下,你可能只需忽略传入的rect并将圆设置为你想要的大小。

    //// Oval Drawing
    var ovalPath = UIBezierPath(ovalInRect: CGRectMake(0, 0, 300, 300))
    UIColor.whiteColor().setFill()
    ovalPath.fill()

3
这应该是被接受的答案。ovalInRect 是正确的方法。其他方法只是解决问题的临时方法。 - geekay

0

唯一正确的方法:

private lazy var whiteCoin: CAShapeLayer = {
    let c = CAShapeLayer()
    c.path = UIBezierPath(ovalIn: bounds).cgPath
    c.fillColor = UIColor.white.cgColor
    layer.addSublayer(c)
    return c
}()

这样就可以实现一个图层,正如你想要的那样。

在iOS中,当视图被调整大小/重绘时,您必须正确地调整任何负责的图层。

如何做到这一点? 这就是 layoutSubviews 的存在意义所在。

class ProperExample: UIView {
    open override func layoutSubviews() {
        super.layoutSubviews()
        whiteCoin.frame = bounds
    }
}

就是这么简单。

class ProperExample: UIView {
    open override func layoutSubviews() {
        super.layoutSubviews()
        whiteCoin.frame = bounds
    }
    private lazy var whiteCoin: CAShapeLayer = {
        let c = CAShapeLayer()
        c.path = UIBezierPath(ovalIn: bounds).cgPath
        c.fillColor = UIColor.white.cgColor
        layer.addSublayer(c)
        return c
    }()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接