1

Some of the frames of my views can be set only after layoutSubviews has been called:

class CustomButton: UIButton {

    let border = CAShapeLayer()

    init() {
        super.init(frame: CGRectZero)

        border.fillColor = UIColor.whiteColor().CGColor
        layer.insertSublayer(border, atIndex: 0)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        border.frame = layer.bounds
        border.path = UIBezierPath(rect: bounds).CGPath
    }
}

Because I want to animate border in a later state, I only want the code in layoutSubviews to be called once. To do that, I use the following code:

var initial = true

override func layoutSubviews() {
    super.layoutSubviews()

    if initial {
        border.frame = layer.bounds
        border.path = UIBezierPath(rect: bounds).CGPath

        initial = false
    }
}

Question:

I was wondering if there is a better way of doing this. A more elegant and functional way, without having to use an extra variable.

Henny Lee
  • 2,970
  • 3
  • 20
  • 37

2 Answers2

0

There is a way to do it without an extra variable (albeit not particularly elegant too) which relies on lazy static properties initialization:

class CustomButton: UIButton {
    struct InitBorder {
        // The static property definition
        static let run: Void = {
            border.frame = layer.bounds
            border.path = UIBezierPath(rect: bounds).CGPath
        }()
    }

    let border = CAShapeLayer()

    init() {
        super.init(frame: CGRectZero)

        border.fillColor = UIColor.whiteColor().CGColor
        layer.insertSublayer(border, atIndex: 0)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        // The call which initializes the static property
        let _ = InitBorder.run
    }
}
Valentin
  • 10,769
  • 2
  • 17
  • 27
-2
let initial = false

override func layoutSubviews() {
    super.layoutSubviews()

    if initial {
        border.frame = layer.bounds
        border.path = UIBezierPath(rect: bounds).CGPath

        initial = false
    }
}
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
Rahul
  • 23
  • 6
  • By initializing `initial` to false, the code in the `if`-block never runs. Besides, it should be `var initial` if its value is to be changed. – Valentin Mar 27 '16 at 22:54