创建一个
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)
}
}
现在,我做了这个可设计(所以如果你把它放在一个单独的框架目标中,你可以在你的故事板中添加这个视图并看到它在那里渲染)。如果您不使用故事板,它仍然有效。这样做很方便:
我还使用了相对坐标(值范围从零到一),并有一种将它们转换为实际坐标的方法,但如果需要,您可以对坐标进行硬编码。但是使用它作为从零到一的值,您将拥有一个可以参与自动布局的角度视图,而无需担心更改特定的坐标值。
最后,一些看似微不足道的小事情,但我在
path
中构造了 layoutSubviews
:这样,当视图大小发生变化(无论是通过自动布局还是编程更改)时,视图将正确地重新渲染。同样,通过使用 didSet
代表 fillColor
和 points
,如果您更改其中任何一个,视图将会为您重新渲染。
您可以根据需要随意更改此设置,但希望这说明了仅拥有
CAShapeLayer
和自定义 path
的基本想法。
如果您使用
insertSublayer
,则可以将其与 AngleView 的其他子视图组合,例如:
我正在使用类似的东西,效果很好,你可以将任何你想要的东西添加到视图中
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
}
}
出于此类目的,我将
UIImageView
与 SVG 内容一起使用。
bounds
、frame
、layer
之类的东西对我来说不适用于不同的屏幕尺寸。如果我正确设置约束,图像视图就会执行我想要的操作,并且由于我使用矢量图像 (SVG),它将正确缩放。
将此片段用于三角形:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="100" height="100">
<polygon points="0,100 100,100 100,100 0,100" fill="white" />
将其另存为 .svg 文件并将其拉入您的资源中。使用此图像将图像视图添加到您的视图中,然后您就准备好了。