Swift Bezier Path在添加Line Method后没有响应
Swift Bezierpath doesnt response after addLine Method
我正在尝试使用 bezierPath 绘制我的视图,我的代码是?
class auctionCollectionView : UIView{
let gradient = CAGradientLayer()
private var shapeLayer: CALayer?
private func addShape() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = mys2().cgPath
shapeLayer.strokeColor = UIColor.lightGray.cgColor
self.shapeLayer = shapeLayer
let colorTop = UIColor(hexFromString: "#101820").cgColor
let colorBottom = UIColor(hexFromString: "#101820").cgColor
let gradientLayer = CAGradientLayer()
gradientLayer.mask = shapeLayer
gradientLayer.colors = [colorTop, colorBottom]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.frame = mys2().bounds
self.layer.insertSublayer(gradientLayer, at:0)
}
override func draw(_ rect: CGRect) {
self.addShape()
}
func mys2() -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: self.frame.height/4)) // start top left
path.addQuadCurve(to: CGPoint(x: self.frame.width , y:self.frame.height/4), controlPoint: CGPoint(x: self.frame.width/2 , y: 0 ))
path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height * 3/4))
path.addQuadCurve(to: CGPoint(x: 0, y: self.frame.height * 3/4), controlPoint: CGPoint(x: self.frame.width/2, y:self.frame.height / 2))
path.addLine(to: CGPoint(x: 0, y: self.frame.height/4))
path.close()
return path
}
}
输出看起来像
我的第一个 QuadCurve 看起来不错,但是当我尝试将它添加到从 maxX (self.frame.width)
、 maxY ( self.frame.height * 3/4)
到 minX ( 0)
、 maxY (self.frame.height * 3/4)
和 CGPoint(x: self.frame.width/2, y:self.frame.height / 2)
它起作用喜欢加行
我在这里错过了什么?此致!
你的路径似乎没问题,但我担心你的问题是你在覆盖 draw
方法时调用的内容。
您应该先添加图层,然后再管理它们。或者您应该使用 draw rect 来绘制所有内容而不使用图层。在这种情况下,我建议使用第二个。我不太确定你的完整实现应该如何,但从复制你的路径并查看渐变代码来看,它可能与此类似:
@IBDesignable class DrawingView: UIView {
@IBInspectable var topColor: UIColor? = .red
@IBInspectable var bottomColor: UIColor? = .blue
private func mys2() -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: self.frame.height/4)) // start top left
path.addQuadCurve(to: CGPoint(x: self.frame.width , y:self.frame.height/4), controlPoint: CGPoint(x: self.frame.width/2 , y: 0 ))
path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height * 3/4))
path.addQuadCurve(to: CGPoint(x: 0, y: self.frame.height * 3/4), controlPoint: CGPoint(x: self.frame.width/2, y:self.frame.height / 2))
path.addLine(to: CGPoint(x: 0, y: self.frame.height/4))
path.close()
return path
}
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext(), let topColor = topColor, let bottomColor = bottomColor else {
return
}
// Save because of clipping
context.saveGState()
// Add clipping from my path
mys2().addClip()
let locations: [CGFloat] = [0.0, 1.0]
let colors = [topColor.cgColor, bottomColor.cgColor]
if let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as CFArray, locations: locations) {
context.drawLinearGradient(gradient, start: CGPoint.zero, end: CGPoint(x: 0.0, y: frame.size.height), options: CGGradientDrawingOptions(rawValue: 0))
}
context.restoreGState()
}
}
所以我们可以只使用裁剪来代替蒙版,这就是蒙版在图层中首先所做的事情。梯度代码有点不同,但仍然足够相似。
现在请注意,只要视图需要重绘,就会调用此方法。要强制重绘,您需要调用 setNeedsDisplay
。所以像下面这样的东西可能很常见:
@IBInspectable var topColor: UIColor? = .red { didSet { refresh() } }
@IBInspectable var bottomColor: UIColor? = .blue { didSet { refresh() } }
override var frame: CGRect { didSet { refresh() } }
override func layoutSubviews() {
super.layoutSubviews()
refresh()
}
private func refresh() { setNeedsDisplay() }
所以基本上你强制它重绘时:
- 任何颜色变化
- 正在设置框架(通常情况下不使用 auto-layout)
- 正在布局子视图(使用 auto-layout 时的通常情况)
注意调用setNeedsDisplay
不会强制立即重载,调用draw
方法。它只是将组件标记为脏,并会在下一个循环中重绘它。结果是,即使在同一个循环(堆栈、方法...)中多次调用 setNeedsDisplay
,draw
也只会被调用一次。所以没有性能问题。
在您的情况下,使用图层也可以完成同样的操作。每当发生变化时,您都需要一个 refresh
方法。那么这个方法应该创建子层或更正子层框架,掩码...并且应该删除 draw
方法。因此,要么使用一种方法,要么使用另一种方法,但不能同时使用这两种方法。
我正在尝试使用 bezierPath 绘制我的视图,我的代码是?
class auctionCollectionView : UIView{
let gradient = CAGradientLayer()
private var shapeLayer: CALayer?
private func addShape() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = mys2().cgPath
shapeLayer.strokeColor = UIColor.lightGray.cgColor
self.shapeLayer = shapeLayer
let colorTop = UIColor(hexFromString: "#101820").cgColor
let colorBottom = UIColor(hexFromString: "#101820").cgColor
let gradientLayer = CAGradientLayer()
gradientLayer.mask = shapeLayer
gradientLayer.colors = [colorTop, colorBottom]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.frame = mys2().bounds
self.layer.insertSublayer(gradientLayer, at:0)
}
override func draw(_ rect: CGRect) {
self.addShape()
}
func mys2() -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: self.frame.height/4)) // start top left
path.addQuadCurve(to: CGPoint(x: self.frame.width , y:self.frame.height/4), controlPoint: CGPoint(x: self.frame.width/2 , y: 0 ))
path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height * 3/4))
path.addQuadCurve(to: CGPoint(x: 0, y: self.frame.height * 3/4), controlPoint: CGPoint(x: self.frame.width/2, y:self.frame.height / 2))
path.addLine(to: CGPoint(x: 0, y: self.frame.height/4))
path.close()
return path
}
}
输出看起来像
我的第一个 QuadCurve 看起来不错,但是当我尝试将它添加到从 maxX (self.frame.width)
、 maxY ( self.frame.height * 3/4)
到 minX ( 0)
、 maxY (self.frame.height * 3/4)
和 CGPoint(x: self.frame.width/2, y:self.frame.height / 2)
它起作用喜欢加行
我在这里错过了什么?此致!
你的路径似乎没问题,但我担心你的问题是你在覆盖 draw
方法时调用的内容。
您应该先添加图层,然后再管理它们。或者您应该使用 draw rect 来绘制所有内容而不使用图层。在这种情况下,我建议使用第二个。我不太确定你的完整实现应该如何,但从复制你的路径并查看渐变代码来看,它可能与此类似:
@IBDesignable class DrawingView: UIView {
@IBInspectable var topColor: UIColor? = .red
@IBInspectable var bottomColor: UIColor? = .blue
private func mys2() -> UIBezierPath {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: self.frame.height/4)) // start top left
path.addQuadCurve(to: CGPoint(x: self.frame.width , y:self.frame.height/4), controlPoint: CGPoint(x: self.frame.width/2 , y: 0 ))
path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height * 3/4))
path.addQuadCurve(to: CGPoint(x: 0, y: self.frame.height * 3/4), controlPoint: CGPoint(x: self.frame.width/2, y:self.frame.height / 2))
path.addLine(to: CGPoint(x: 0, y: self.frame.height/4))
path.close()
return path
}
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext(), let topColor = topColor, let bottomColor = bottomColor else {
return
}
// Save because of clipping
context.saveGState()
// Add clipping from my path
mys2().addClip()
let locations: [CGFloat] = [0.0, 1.0]
let colors = [topColor.cgColor, bottomColor.cgColor]
if let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as CFArray, locations: locations) {
context.drawLinearGradient(gradient, start: CGPoint.zero, end: CGPoint(x: 0.0, y: frame.size.height), options: CGGradientDrawingOptions(rawValue: 0))
}
context.restoreGState()
}
}
所以我们可以只使用裁剪来代替蒙版,这就是蒙版在图层中首先所做的事情。梯度代码有点不同,但仍然足够相似。
现在请注意,只要视图需要重绘,就会调用此方法。要强制重绘,您需要调用 setNeedsDisplay
。所以像下面这样的东西可能很常见:
@IBInspectable var topColor: UIColor? = .red { didSet { refresh() } }
@IBInspectable var bottomColor: UIColor? = .blue { didSet { refresh() } }
override var frame: CGRect { didSet { refresh() } }
override func layoutSubviews() {
super.layoutSubviews()
refresh()
}
private func refresh() { setNeedsDisplay() }
所以基本上你强制它重绘时:
- 任何颜色变化
- 正在设置框架(通常情况下不使用 auto-layout)
- 正在布局子视图(使用 auto-layout 时的通常情况)
注意调用setNeedsDisplay
不会强制立即重载,调用draw
方法。它只是将组件标记为脏,并会在下一个循环中重绘它。结果是,即使在同一个循环(堆栈、方法...)中多次调用 setNeedsDisplay
,draw
也只会被调用一次。所以没有性能问题。
在您的情况下,使用图层也可以完成同样的操作。每当发生变化时,您都需要一个 refresh
方法。那么这个方法应该创建子层或更正子层框架,掩码...并且应该删除 draw
方法。因此,要么使用一种方法,要么使用另一种方法,但不能同时使用这两种方法。