0
votes

I'm in the process of learning how to create custom UIViews. This specific view I'm making contains a couple buttons. I noticed when I call the frame/height property from within the lazy instantiation block, I get the value 128, but when I call the height property on the rect argument passed in the drawRect function along with the bounds, I get the value 94.

I don't understand why the bounds/frame width/height properties called from the drawRect function don't align with the frame/bounds height and width used in the initializer. Can someone explain this?

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

Edit:

I create the GroupingMetaDataView from the ViewController. YardageMetaDataView is a subclass of GroupingMetaDataView. The YardageMetaDataView doesn't perform any custom drawing.

I noticed the documentation for the drawRect parameter states that

The portion of the view's bounds that needs to be updated. The first time your view is drawn, this rectangle is typically the entire visible bounds of your view. However, during subsequent drawing operations, the rectangle may specify only part of your view.

When and why would the parameter, rect, specify only part of the view? The drawRect is called on the next drawing cycle, after setNeedsDisplay is triggered. SetNeedsDisplay doesn't take any parameters, so I'm assuming the parameter represents the entire view?

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
  }()
}
1
Where's the code where you're adding it to a parent view?nhgrif
@nhgrif I just added the codes that instantiates the view.trav.chung

1 Answers

0
votes

There is another method similar to setNeedsDisplay called setNeedsDisplay(_:). When the latter is called, the parameter passed to drawRect(_:) is the one you passed in that call. That rectangle area is marked invalid and needs to be redrawn.

I don't know whether you have called setNeedsDisplay(_:) or not. It's your job to find out. Good luck. :)