Search code examples
iosswiftxcodecocoaxib

Reusable .xib + cocoa class components, how to auto size and style superview in storyboard?


I have implemented reusable button component using combination of .xib and cocoa class following this guide

It works, but there is an issue. In order to use it in one of my main View Storyboards I have to first drag in a normal view (referenced as superview in question title) and then apply my Button class, to make it a button.

This works, but initial view height and width alongside its white background persist, so I have to always manually rewrite those when I use my component, which in itself results in poor reusability.

Ideally, I'd like to drag in a view, set it to Button class and thats it, that view should instantly take buttons height and width and have transparent background. Is something like this achievable?

To light more context on this issue here are few useful bits of my implementation

1. Reusable component made as a .xib view and its own cocoa class

enter image description here

2. Contents of Button.swift

import UIKit

@IBDesignable class Button: UIView {

    @IBOutlet var contentView: UIView!
    @IBOutlet weak var label: UILabel!

  @IBInspectable var buttonLabel: String? {
    get {
      return label.text
    }
    set(buttonLabel) {
      label.text = buttonLabel
    }
  }

  override init(frame: CGRect) {
    super.init(frame: frame)
    componentInit()
  }

  required init?(coder: NSCoder) {
    super.init(coder: coder)
    componentInit()
  }

  private func componentInit() {
    let bundle = Bundle(for: Button.self)
    bundle.loadNibNamed("Button", owner: self, options: nil)
    addSubview(contentView)
    contentView.frame = self.bounds
    contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
  }

}

3. Example usage (inside one of my main view storyboards) demonstrating how ordinary view is turned into a button, but has issues with height, width and background color

enter image description here

P.S ^ if its hard to tell what is going on in a gif above, I basically drag UIView into a story board and give it custom class attribute of Button, this turns that view into a button.

EDIT: Just to make it clearer, my question is: Can I apply width, height and transparent colour to my XIB's parent / super view? End goal here is to just drag in a view onto storyboard, give it custom class of a Button and thats it, it should be sized properly and have transparent background, as opposed to how it is at the moment (view doesn't get sized as button and has white background)


Solution

  • You have to pin your subviews in Button properly and also in Main.storyboard. Then your custom view will autosize. And clear color is working.

    enter image description here enter image description here enter image description here

    import UIKit
    
    @IBDesignable
    class Button: UIView {
    
        @IBOutlet var contentView: UIView!
        @IBOutlet weak var label: UILabel!
    
        @IBInspectable
        var backColor: UIColor = .clear {
            didSet {
                backgroundColor = backColor
                contentView.backgroundColor = backColor
            }
        }
    
        override var backgroundColor: UIColor? {
            get {
                return backgroundColor
            } set {
    
            }
        }
    
        @IBInspectable
        var buttonLabel: String? {
            get {
                return label.text
            }
            set(buttonLabel) {
                label.text = buttonLabel
            }
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            componentInit()
        }
    
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            componentInit()
        }
    
        private func componentInit() {
            let bundle = Bundle(for: Button.self)
            bundle.loadNibNamed("Button", owner: self, options: nil)
            addSubview(contentView)
            contentView.frame = bounds
            backgroundColor = backColor
            contentView.backgroundColor = backColor
            contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
            // for static height
            contentView.heightAnchor.constraint(equalToConstant: 70).isActive = true
        }
    
    }
    


    To ensure you CustomView would size itself properly, you can use bottom constraint >= 0. After testing reset to equals.

    enter image description here