UIView 边界/框架与 drawRect 不匹配

Posted

技术标签:

【中文标题】UIView 边界/框架与 drawRect 不匹配【英文标题】:UIView bounds/frame not matching up with drawRect 【发布时间】:2016-08-21 19:36:11 【问题描述】:

我正在学习如何创建自定义 UIView。我正在制作的这个特定视图包含几个按钮。我注意到,当我从惰性实例化块中调用 frame/height 属性时,我得到的值是 128,但是当我调用 drawRect 函数中传递的 rect 参数的 height 属性以及边界时,我得到的值是 94。

我不明白为什么从 drawRect 函数调用的边界/框架宽度/高度属性与初始化程序中使用的框架/边界高度和宽度不一致。有人可以解释一下吗?

@IBDesignable
class GroupingMetaDataView: UIView 

    @IBInspectable var strokeColor: UIColor =
        UIColor.blackColor().colorWithAlphaComponent(0.4)

    @IBInspectable var strokeWidth: CGFloat = 2.0


    lazy var subButton: AddButton! = 
        print("frame height: \(self.frame.height)")
        print("bounds height: \(self.bounds.height)")
        let width = self.frame.width * 0.087
        let size = CGSize(width: width, height: width)
        let frame = CGRect(origin: CGPoint(x: self.frame.width * 0.055,
                                           y: self.frame.height * 0.5), size: size)
        let button = AddButton(frame: frame, isAddButton: false)

        return button
    ()

    lazy var addButton: AddButton! = 
        let width = self.frame.width * 0.087
        let size = CGSize(width: width, height: width)
        let frame = CGRect(origin: CGPoint(x: self.frame.width * 0.857,
                                           y: self.frame.height), size: size)
        let button = AddButton(frame: frame, isAddButton: true)

        return button
    ()

    override init(frame: CGRect) 
        super.init(frame: frame)

        self.setupUI()

    

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
        self.setupUI()
    

    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func drawRect(rect: CGRect) 
        // Drawing code
        print("rect height: \(rect.height)")
        print("boundsheight: \(bounds.height)")

        let context = UIGraphicsGetCurrentContext()
        CGContextSetLineWidth(context, strokeWidth)
        strokeColor.setStroke()

        let topBarPath = UIBezierPath()
        topBarPath.moveToPoint(CGPoint(x: 0.0, y: 2.0))
        topBarPath.addLineToPoint(CGPoint(x: rect.width, y: 2.0))

        topBarPath.lineWidth = strokeWidth
        topBarPath.stroke()

        let bottomBarPath = UIBezierPath()
        bottomBarPath.moveToPoint(CGPoint(x: 0.0, y: rect.height-2.0))
        bottomBarPath.addLineToPoint(CGPoint(x: rect.width, y: rect.height-2.0))

        bottomBarPath.lineWidth = strokeWidth
        bottomBarPath.stroke()
    

    // MARK: Setup

    func setupUI() 
        self.backgroundColor = UIColor.yellowColor()
        addSubview(subButton)
        addSubview(addButton)
    

编辑:

我从 ViewController 创建 GroupingMetaDataView。 YardageMetaDataView 是 GroupingMetaDataView 的子类。 YardageMetaDataView 不执行任何自定义绘图。

我注意到 drawRect 参数的文档指出

需要更新的视图边界部分。首先 绘制视图时,此矩形通常是整个 视图的可见边界。然而,在随后的绘图中 操作,矩形可能只指定视图的一部分。

参数 rect 何时以及为何仅指定视图的一部分?在触发 setNeedsDisplay 之后,在下一个绘图周期调用 drawRect。 SetNeedsDisplay 不带任何参数,所以我假设参数代表整个视图?

ViewController.swift

class ViewController: UIViewController 

// MARK: - Properties

  lazy var yMetaDataView: YardageMetaDataView! = 
      let view = YardageMetaDataView(frame: CGRect(origin: CGPoint(x: 50, y: 100),
                                   size: CGSize(width: self.view.bounds.width * 0.75,
                                                height: self.view.bounds.height * 0.102)))
      view.translatesAutoresizingMaskIntoConstraints = false
      return view
  ()

【问题讨论】:

将代码添加到父视图的代码在哪里? @nhgrif 我刚刚添加了实例化视图的代码。 【参考方案1】:

还有另一种类似于 setNeedsDisplay 的方法,称为 setNeedsDisplay(_:)。当调用后者时,传递给 drawRect(_:) 的参数就是您在该调用中传递的参数。该矩形区域被标记为无效,需要重新绘制。

不知道你有没有调用setNeedsDisplay(_:)。找出答案是你的工作。祝你好运。 :)

【讨论】:

以上是关于UIView 边界/框架与 drawRect 不匹配的主要内容,如果未能解决你的问题,请参考以下文章

UIView 的边界矩形可以大于框架矩形是不是有意义?

自定义 UI 视图更改帧大小

正确使用 DrawRect 覆盖 - 我可以防止视图拉伸吗?

iOS drawRect的作用和调用机制

具有非矩形边界的 UIDynamicItem

UIScrollView中的drawRect裁剪