2

I have a custom UIView and I add it to my ViewController like this:

let myCustomView = Bundle.main.loadNibNamed("MyCustomView", owner: nil, options: nil) as! MyCustomView
myCustomView.layer.cornerRadius = 10
myCustomView.layer.masksToBounds = true

I round the corners of the view. But I am wondering, is there a way to move this logic of rounding the corners inside the MyCustomView class?

BlueBoy
  • 798
  • 1
  • 11
  • 22

3 Answers3

4

As you use IB, you may find it more convenient to make an extension of UIView

extension UIView {
    @IBInspectable var borderColor: UIColor? {
        set {
            layer.borderColor = newValue?.cgColor
        }
        get {
            if let color = layer.borderColor {
                return UIColor(cgColor:color)
            } else {
                return nil
            }
        }
    }

    @IBInspectable var borderWidth: CGFloat {
        set {
            layer.borderWidth = newValue
        }
        get {
            return layer.borderWidth
        }
    }

    @IBInspectable var cornerRadius: CGFloat {
        set {
            layer.cornerRadius = newValue
            clipsToBounds = newValue > 0
        }
        get {
            return layer.cornerRadius
        }
    }
}

Then you can set those values from Attributes inspector.

enter image description here

Lawliet
  • 3,438
  • 2
  • 17
  • 28
  • Awesome solution :) – Rajamohan S Jul 04 '17 at 06:19
  • I really can't see why this is considered a good solution. You're exposing these properties to every single UIView class whereas the question was asking about one specific subclass. I would imagine this would slow down the loading of a storyboard considerably too. – Leon Jul 04 '17 at 11:00
  • @Leon "considerably" sounds a bit heavy. I've stated that "if you use IB" and "for convenience". I also agree with the overhead pointed out. – Lawliet Jul 04 '17 at 11:12
  • Perhaps, although it looks like the UIView doesn't render in the storyboard anyway so there's no real impact. However, this was not the main issue raised. – Leon Jul 04 '17 at 11:29
2

Yes - If you're loading a nib with a custom view, that nib is very likely referring to another class. If that's the case, you can move the logic inside the class itself.

A screenshot illustrating Xcode's Interface Builder

That said, I really like Lawliet's suggestion of making a UIView extension with IBInspectable properties. The downside to that approach is that every single view now has these properties, which creates a certain overhead and potential for clashes.

Moshe
  • 57,511
  • 78
  • 272
  • 425
0

You can do something like this in your UIView subclass:

class RoundedView: UIView {

    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.layer.cornerRadius = 10
        self.layer.masksToBounds = true
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.layer.cornerRadius = 10
        self.layer.masksToBounds = true
    }

}

Also if you want to pass a custom value instead of '10' in the cornerRadius property, you can try to implement a convenience init by looking here:

Override Init method of UIView in Swift

Rishabh
  • 465
  • 5
  • 14
  • this is what i am looking for but getting `fatal error: init(coder:) has not been implemented` when I run it – BlueBoy Jul 04 '17 at 06:19
  • try to add this in init coder function super.init(coder: aDecoder) – Rishabh Jul 04 '17 at 09:51
  • that stops the crash, but has no effect. – BlueBoy Jul 04 '17 at 16:08
  • Oh...my bad. You are loading the view from a nib file. That will cause init(coder:) to be called instead of init(frame:). So you need those 2 lines for setting the layer property in init(coder:) function as well. I have updated my answer. – Rishabh Jul 05 '17 at 10:39