答案 0 :(得分:12)
创建CAShapeLayer
并提供path
和fillColor
:
@IBDesignable
public class AngleView: UIView {
@IBInspectable public var fillColor: UIColor = .blue { didSet { setNeedsLayout() } }
var points: [CGPoint] = [
.zero,
CGPoint(x: 1, y: 0),
CGPoint(x: 1, y: 1),
CGPoint(x: 0, y: 0.5)
] { didSet { setNeedsLayout() } }
private lazy var shapeLayer: CAShapeLayer = {
let _shapeLayer = CAShapeLayer()
self.layer.insertSublayer(_shapeLayer, at: 0)
return _shapeLayer
}()
override public func layoutSubviews() {
shapeLayer.fillColor = fillColor.cgColor
guard points.count > 2 else {
shapeLayer.path = nil
return
}
let path = UIBezierPath()
path.move(to: convert(relativePoint: points[0]))
for point in points.dropFirst() {
path.addLine(to: convert(relativePoint: point))
}
path.close()
shapeLayer.path = path.cgPath
}
private func convert(relativePoint point: CGPoint) -> CGPoint {
return CGPoint(x: point.x * bounds.width + bounds.origin.x, y: point.y * bounds.height + bounds.origin.y)
}
}
现在,我做了这个designable(所以如果你把它放在一个单独的框架目标中,你可以在你的故事板中添加这个视图并看到它在那里呈现)。如果你不使用故事板,它仍然有效。这样做很方便:
我还使用了相对坐标(值从0到1)并且有一个方法可以将它们转换为实际坐标,但如果需要,可以对坐标进行硬编码。但是使用此值作为从零到一的值,您可以使用角度视图参与自动布局,而无需担心更改特定坐标值。
最后,可能看似微不足道的小事,但我在path
中构建layoutSubviews
:这样,当视图改变大小时(无论是通过自动布局还是程序化更改),视图将正确地重新渲染。同样,对didSet
和fillColor
使用points
,如果您更改其中任何一个,视图将会为您重新呈现。
您可以根据需要随意更改此内容,但希望这可以说明仅使用自定义CAShapeLayer
path
的基本想法。
如果您使用insertSublayer
,则可以将其与AngleView的其他子视图结合使用,例如:
答案 1 :(得分:2)
我正在使用这样的东西并且工作正常,你可以在视图中添加你想要的任何东西
import UIKit
class CustomView: UIView {
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
// Get Height and Width
let layerHeight = layer.frame.height
let layerWidth = layer.frame.width
// Create Path
let bezierPath = UIBezierPath()
// Points
let pointA = CGPoint(x: 0, y: 0)
let pointB = CGPoint(x: layerWidth, y: 0)
let pointC = CGPoint(x: layerWidth, y: layerHeight)
let pointD = CGPoint(x: 0, y: layerHeight*2/3)
// Draw the path
bezierPath.move(to: pointA)
bezierPath.addLine(to: pointB)
bezierPath.addLine(to: pointC)
bezierPath.addLine(to: pointD)
bezierPath.close()
// Mask to Path
let shapeLayer = CAShapeLayer()
shapeLayer.path = bezierPath.cgPath
layer.mask = shapeLayer
}
}