let block = UIView(frame: CGRectMake(cellWidth-25, cellHeight/2-8, 16, 16))
block.backgroundColor = UIColor(netHex: 0xff3b30)
block.layer.cornerRadius = 9
block.clipsToBounds = true
这就是我现在所拥有的,但是显然这不是正确的方法。
最简单的方法是什么?
let block = UIView(frame: CGRectMake(cellWidth-25, cellHeight/2-8, 16, 16))
block.backgroundColor = UIColor(netHex: 0xff3b30)
block.layer.cornerRadius = 9
block.clipsToBounds = true
这就是我现在所拥有的,但是显然这不是正确的方法。
最简单的方法是什么?
Answers:
警告!这是不正确的解决方案。在
drawRect
方法中无限添加图层(每次绘制视图时)。您永远不要在drawRect
方法中添加图层。使用layoutSubview
代替。
您可以以此绘制一个圆(Swift 3.0+):
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 100, y: 100), radius: CGFloat(20), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
// Change the fill color
shapeLayer.fillColor = UIColor.clear.cgColor
// You can change the stroke color
shapeLayer.strokeColor = UIColor.red.cgColor
// You can change the line width
shapeLayer.lineWidth = 3.0
view.layer.addSublayer(shapeLayer)
使用您发布的代码,您可以裁剪的角落,而UIView
不是在视图中添加圆圈。
这是使用该方法的完整示例:
/// A special UIView displayed as a ring of color
class Ring: UIView {
override func drawRect(rect: CGRect) {
drawRingFittingInsideView()
}
internal func drawRingFittingInsideView() -> () {
let halfSize:CGFloat = min( bounds.size.width/2, bounds.size.height/2)
let desiredLineWidth:CGFloat = 1 // your desired value
let circlePath = UIBezierPath(
arcCenter: CGPoint(x:halfSize,y:halfSize),
radius: CGFloat( halfSize - (desiredLineWidth/2) ),
startAngle: CGFloat(0),
endAngle:CGFloat(M_PI * 2),
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = UIColor.redColor().CGColor
shapeLayer.lineWidth = desiredLineWidth
layer.addSublayer(shapeLayer)
}
}
请注意,但是有一个非常方便的电话:
let circlePath = UIBezierPath(ovalInRect: rect)
这会完成所有的工作。(不要忘了用线条粗细来插入它,使用CGRectInset
。也非常容易。)
internal func drawRingFittingInsideView(rect: CGRect) {
let desiredLineWidth:CGFloat = 4 // Your desired value
let hw:CGFloat = desiredLineWidth/2
let circlePath = UIBezierPath(ovalInRect: CGRectInset(rect,hw,hw))
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = UIColor.redColor().CGColor
shapeLayer.lineWidth = desiredLineWidth
layer.addSublayer(shapeLayer)
}
在Swift的实践中,您肯定会使用@IBDesignable
和@IBInspectable
。使用这些,您实际上可以在情节提要中查看和更改渲染!
如您所见,它实际上在情节提要上向检查器添加了新功能,您可以在情节提要上对其进行更改:
/// A dot with a border, which you can control completely in Storyboard
@IBDesignable class Dot: UIView {
@IBInspectable var mainColor: UIColor = UIColor.blueColor() {
didSet {
print("mainColor was set here")
}
}
@IBInspectable var ringColor: UIColor = UIColor.orangeColor() {
didSet {
print("bColor was set here")
}
}
@IBInspectable var ringThickness: CGFloat = 4 {
didSet {
print("ringThickness was set here")
}
}
@IBInspectable var isSelected: Bool = true
override func drawRect(rect: CGRect) {
let dotPath = UIBezierPath(ovalInRect:rect)
let shapeLayer = CAShapeLayer()
shapeLayer.path = dotPath.CGPath
shapeLayer.fillColor = mainColor.CGColor
layer.addSublayer(shapeLayer)
if (isSelected) {
drawRingFittingInsideView(rect)
}
}
internal func drawRingFittingInsideView(rect: CGRect) {
let hw:CGFloat = ringThickness/2
let circlePath = UIBezierPath(ovalInRect: CGRectInset(rect,hw,hw) )
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = ringColor.CGColor
shapeLayer.lineWidth = ringThickness
layer.addSublayer(shapeLayer)
}
}
最后,请注意,如果您有一个UIView
(是正方形,并且在情节提要中设置为红色),并且只想将其变成红色圆圈,则可以执行以下操作:
// Makes a UIView into a circular dot of color
class Dot: UIView {
override func layoutSubviews() {
layer.cornerRadius = bounds.size.width/2
}
}
M_PI
不推荐使用。现在Double.pi
(在Swift 3中)
func drawRect(rect: CGRect)
方法中添加新的CALayer可能不是一个好主意,因为该方法应该在自己的层中进行自定义绘制,因此该方法也称为多次。
如果要使用UIView进行绘制,则需要将半径/设置为高度或宽度。
所以只需更改:
block.layer.cornerRadius = 9
至:
block.layer.cornerRadius = block.frame.width / 2
但是,您需要使高度和宽度相同。如果您想使用核心图形,则需要执行以下操作:
CGContextRef ctx= UIGraphicsGetCurrentContext();
CGRect bounds = [self bounds];
CGPoint center;
center.x = bounds.origin.x + bounds.size.width / 2.0;
center.y = bounds.origin.y + bounds.size.height / 2.0;
CGContextSaveGState(ctx);
CGContextSetLineWidth(ctx,5);
CGContextSetRGBStrokeColor(ctx,0.8,0.8,0.8,1.0);
CGContextAddArc(ctx,locationOfTouch.x,locationOfTouch.y,30,0.0,M_PI*2,YES);
CGContextStrokePath(ctx);
制作一个类UIView并将此代码分配给它一个简单的圆圈
import UIKit
@IBDesignable
class DRAW: UIView {
override func draw(_ rect: CGRect) {
var path = UIBezierPath()
path = UIBezierPath(ovalIn: CGRect(x: 50, y: 50, width: 100, height: 100))
UIColor.yellow.setStroke()
UIColor.red.setFill()
path.lineWidth = 5
path.stroke()
path.fill()
}
}
Swift 4版本接受的答案:
@IBDesignable
class CircledDotView: UIView {
@IBInspectable var mainColor: UIColor = .white {
didSet { print("mainColor was set here") }
}
@IBInspectable var ringColor: UIColor = .black {
didSet { print("bColor was set here") }
}
@IBInspectable var ringThickness: CGFloat = 4 {
didSet { print("ringThickness was set here") }
}
@IBInspectable var isSelected: Bool = true
override func draw(_ rect: CGRect) {
let dotPath = UIBezierPath(ovalIn: rect)
let shapeLayer = CAShapeLayer()
shapeLayer.path = dotPath.cgPath
shapeLayer.fillColor = mainColor.cgColor
layer.addSublayer(shapeLayer)
if (isSelected) {
drawRingFittingInsideView(rect: rect)
}
}
internal func drawRingFittingInsideView(rect: CGRect) {
let hw: CGFloat = ringThickness / 2
let circlePath = UIBezierPath(ovalIn: rect.insetBy(dx: hw, dy: hw))
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = ringColor.cgColor
shapeLayer.lineWidth = ringThickness
layer.addSublayer(shapeLayer)
}
}
为Xcode 8.2.2,Swift 3.x更新@Dario的代码方法。注意在情节提要中,将“背景”颜色设置为“清除”,以避免在方形UIView中出现黑色背景:
import UIKit
@IBDesignable
class Dot:UIView
{
@IBInspectable var mainColor: UIColor = UIColor.clear
{
didSet { print("mainColor was set here") }
}
@IBInspectable var ringColor: UIColor = UIColor.clear
{
didSet { print("bColor was set here") }
}
@IBInspectable var ringThickness: CGFloat = 4
{
didSet { print("ringThickness was set here") }
}
@IBInspectable var isSelected: Bool = true
override func draw(_ rect: CGRect)
{
let dotPath = UIBezierPath(ovalIn: rect)
let shapeLayer = CAShapeLayer()
shapeLayer.path = dotPath.cgPath
shapeLayer.fillColor = mainColor.cgColor
layer.addSublayer(shapeLayer)
if (isSelected) { drawRingFittingInsideView(rect: rect) }
}
internal func drawRingFittingInsideView(rect: CGRect)->()
{
let hw:CGFloat = ringThickness/2
let circlePath = UIBezierPath(ovalIn: rect.insetBy(dx: hw,dy: hw) )
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = ringColor.cgColor
shapeLayer.lineWidth = ringThickness
layer.addSublayer(shapeLayer)
}
}
如果要控制起点和终点角度:
import UIKit
@IBDesignable
class Dot:UIView
{
@IBInspectable var mainColor: UIColor = UIColor.clear
{
didSet { print("mainColor was set here") }
}
@IBInspectable var ringColor: UIColor = UIColor.clear
{
didSet { print("bColor was set here") }
}
@IBInspectable var ringThickness: CGFloat = 4
{
didSet { print("ringThickness was set here") }
}
@IBInspectable var isSelected: Bool = true
override func draw(_ rect: CGRect)
{
let dotPath = UIBezierPath(ovalIn: rect)
let shapeLayer = CAShapeLayer()
shapeLayer.path = dotPath.cgPath
shapeLayer.fillColor = mainColor.cgColor
layer.addSublayer(shapeLayer)
if (isSelected) { drawRingFittingInsideView(rect: rect) }
}
internal func drawRingFittingInsideView(rect: CGRect)->()
{
let halfSize:CGFloat = min( bounds.size.width/2, bounds.size.height/2)
let desiredLineWidth:CGFloat = ringThickness // your desired value
let circlePath = UIBezierPath(
arcCenter: CGPoint(x: halfSize, y: halfSize),
radius: CGFloat( halfSize - (desiredLineWidth/2) ),
startAngle: CGFloat(0),
endAngle:CGFloat(Double.pi),
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = ringColor.cgColor
shapeLayer.lineWidth = ringThickness
layer.addSublayer(shapeLayer)
}
}
一个简单的函数,使用乘数百分比在窗口框架的中间绘制一个圆
/// CGFloat is a multiplicator from self.view.frame.width
func drawCircle(withMultiplicator coefficient: CGFloat) {
let radius = self.view.frame.width / 2 * coefficient
let circlePath = UIBezierPath(arcCenter: self.view.center, radius: radius, startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
//change the fill color
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.darkGray.cgColor
shapeLayer.lineWidth = 2.0
view.layer.addSublayer(shapeLayer)
}
在视图中添加确实加载了
//Circle Points
var CircleLayer = CAShapeLayer()
let center = CGPoint (x: myCircleView.frame.size.width / 2, y: myCircleView.frame.size.height / 2)
let circleRadius = myCircleView.frame.size.width / 2
let circlePath = UIBezierPath(arcCenter: center, radius: circleRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 4), clockwise: true)
CircleLayer.path = circlePath.cgPath
CircleLayer.strokeColor = UIColor.red.cgColor
CircleLayer.fillColor = UIColor.blue.cgColor
CircleLayer.lineWidth = 8
CircleLayer.strokeStart = 0
CircleLayer.strokeEnd = 1
Self.View.layer.addSublayer(CircleLayer)
一种更容易且资源友好的方法。
import UIKit
@IBDesignable
class CircleDrawView: UIView {
@IBInspectable var borderColor: UIColor = UIColor.red;
@IBInspectable var borderSize: CGFloat = 4
override func draw(_ rect: CGRect)
{
layer.borderColor = borderColor.cgColor
layer.borderWidth = borderSize
layer.cornerRadius = self.frame.height/2
}
}
使用Border Color
和Border Size
和默认Background
属性,可以定义圆的外观。
请注意,要绘制一个圆,视图的高度和宽度必须相等。
该代码适用于Swift >= 4
和Xcode >= 9
。
这是我使用Swift 5和Core Graphics的版本。
我创建了一个班画两个圆。第一个圆是使用创建的addEllipse()
。它将椭圆变成正方形,从而创建一个圆。没有功能我感到惊讶addCircle()
。第二个圆是使用addArc()
2pi弧度创建的
import UIKit
@IBDesignable
class DrawCircles: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {
print("could not get graphics context")
return
}
context.setLineWidth(2)
context.setStrokeColor(UIColor.blue.cgColor)
context.addEllipse(in: CGRect(x: 30, y: 30, width: 50.0, height: 50.0))
context.strokePath()
context.setStrokeColor(UIColor.red.cgColor)
context.beginPath() // this prevents a straight line being drawn from the current point to the arc
context.addArc(center: CGPoint(x:100, y: 100), radius: 20, startAngle: 0, endAngle: 2.0*CGFloat.pi, clockwise: false)
context.strokePath()
}
}
在您的ViewController中didViewLoad()
添加以下内容:
let myView = DrawCircles(frame: CGRect(x: 50, y: 50, width: 300, height: 300))
self.view.addSubview(myView)
它运行时应如下所示。希望您喜欢我的解决方案!