【问题标题】:Parallelogram view using UIBezierPath使用 UIBezierPath 的平行四边形视图
【发布时间】:2019-02-02 19:06:10
【问题描述】:

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

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

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;

    }
}

我创建视图使用

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

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

【问题讨论】:

  • 这很简单——你从offset开始你的顶线,并希望它和你的视图一样长width——这意味着它超出了你的视图范围。您可以检查设置 clipsToBounds = false 是否可以解决问题或更改您的数学以便 offset + parallelogramWidth <= viewWidth
  • @Losiowaty 我试过 self.clipsToBounds = false 但还是不行。

标签: ios swift uiview swift4 uibezierpath


【解决方案1】:

问题是在draw(_:) 中使用frame。问题在于frame 是“视图的大小和位置在其父视图的坐标系中”(强调)。您如何在此视图中渲染此形状通常与此视图在其父视图中的位置无关。如果此视图恰好不在其父视图的 0、0 处,您可能会遇到裁剪。

但也不要使用rect 参数。 “第一次绘制视图时,这个矩形通常是视图的整个可见边界。但是,在随后的绘图操作中,矩形可能只指定了您视图的一部分。”如果操作系统决定只需要更新你的CustomView 的一部分,你就有可能彻底改变形状。

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

@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()
    }

}

顺便说一句,我没有设置面具。如果您正在制作动画,那么每次调用 draw 时不断重置蒙版似乎效率低下。我个人只是将视图的背景颜色设置为.clear。但这与当前的问题无关。

【讨论】:

    【解决方案2】:

    正如@Losiowaty 所建议的那样,数学是错误的,因为右上角超出了框架的范围。 (不知道为什么 clipToBounds=false 不起作用;但这只是一个调试建议 - 不是解决方案)。试试这个:

    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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-16
      • 1970-01-01
      • 2021-10-10
      相关资源
      最近更新 更多