关于ios:使用UIBezierPath的平行四边形视图

Parallelogram view using UIBezierPath

我正在尝试使用UIBezierPath创建自定义平行四边形视图,但没有一个完美的视图。

以下是我的自定义视图代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class CustomView: UIView {
    override func draw(_ rect: CGRect) {
        let offset  = 60.0;
        let path = UIBezierPath()

           path.move(to: CGPoint(x: self.frame.origin.x + CGFloat(offset), y: self.frame.origin.y))
           path.addLine(to: CGPoint(x: self.frame.width + self.frame.origin.x  , y: self.frame.origin.y))
           path.addLine(to: CGPoint(x: self.frame.origin.x + self.frame.width - CGFloat(offset) , y: self.frame.origin.y + self.frame.height))
           path.addLine(to: CGPoint(x: self.frame.origin.x, y: self.frame.origin.y + self.frame.height))


        // Close the path. This will create the last line automatically.
         path.close()
        UIColor.red.setFill()
        path.fill()

        let shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        self.layer.mask = shapeLayer;

    }
}

然后我使用

创建视图

1
2
3
let customView = CustomView()
customView.frame = CGRect(origin: CGPoint(x: 10, y: 20), size: CGSize(width: 250, height: 250))
self.view.addSubview(customView)

但是我得到了这样的视图,它不是完美的平行四边形。

enter


问题是在draw(_:)中使用了frame。问题是frame是视图的大小和位置在其父视图中的坐标系。 (添加了重点)。在此视图中渲染此形状的方式通常与该视图在其父视图中的位置无关。如果此视图恰好不在其父视图的0,0,则可以体验裁剪。

但是也不要使用rect参数。第一次绘制视图时,此矩形通常是视图的整个可见范围。但是,在随后的绘制操作中,矩形可能仅指定视图的一部分。如果操作系统决定只需要更新部分CustomView

,则可能会发生形状发生根本变化的风险。

使用bounds代替,它位于视图自己的坐标系中。而且,使用minXminYmaxXmaxY可以稍微简化代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@IBDesignable
class CustomView: UIView {

    @IBInspectable var offset:    CGFloat = 60        { didSet { setNeedsDisplay() } }
    @IBInspectable var fillColor: UIColor = .red      { didSet { setNeedsDisplay() } }

    override func draw(_ rect: CGRect) {
        let path = UIBezierPath()

        path.move(to: CGPoint(x: bounds.minX + offset, y: bounds.minY))
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
        path.addLine(to: CGPoint(x: bounds.maxX - offset, y: bounds.maxY))
        path.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))

        // Close the path. This will create the last line automatically.
        path.close()
        fillColor.setFill()
        path.fill()
    }

}

enter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class CustomView: UIView {
    override func draw(_ rect: CGRect) {
        let offset: CGFloat = 60.0;

        let path = UIBezierPath()

        let width = self.bounds.width - offset

        let upperLeftPoint = CGPoint(x: self.bounds.origin.x + offset, y: self.bounds.origin.y)
        let upperRightPoint = CGPoint(x: self.bounds.origin.x + width, y: self.bounds.origin.y)

        let lowerRightPoint = CGPoint(x: width - offset, y: self.bounds.size.height)
        let lowerLeftPoint = CGPoint(x: self.bounds.origin.x, y: self.bounds.size.height)

        path.move(to: upperLeftPoint)
        path.addLine(to: upperRightPoint)
        path.addLine(to: lowerRightPoint)
        path.addLine(to: lowerLeftPoint)
        path.addLine(to: upperLeftPoint)

        // Close the path. This will create the last line automatically.
        path.close()
        UIColor.red.setFill()
        path.fill()

        let shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        self.layer.mask = shapeLayer;
    }
}