Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom UIView with Nib in swift without using loadFromNib in the view controller

I've always used the loadNibNamed method for loading custom views into view controllers, but now i'm trying to avoid calling that method outside the custom view for making it more reusable so that if another person uses my custom view he only will need to instantiate the view without loadFromNib, for example:

var myView: MyView = MyView()

And adding this view to the view controller's view would be enough, the custom view will load the nib inside itself. I'm trying to do it in Swift, in ObjC I've found code like the one of this answer: UIView and initWithFrame and a NIB file. How can i get the NIB file loaded? But in swift I can't use the init used in the answer:

- (id)initWithFrame:(CGRect)frame 
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code.
        //
        [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
        [self addSubview:self.view];
    }
    return self;
}

I have this method and it ends with an infinite loop:

override init(frame: CGRect) {
    super.init(frame: frame)
    self.loadFromNibNamed("MyView")
}

I've also tried adding another view inside MyView as a IBOutlet like the other answer says and using all the inits:

@IBOutlet var view: UIView!

override init() {
    super.init()
    NSBundle.mainBundle().loadNibNamed("MediaPlayerView", owner: self, options: nil)
    self.addSubview(self.view)
}

override init(frame: CGRect) {
    super.init(frame: frame)
    NSBundle.mainBundle().loadNibNamed("MediaPlayerView", owner: self, options: nil)
    self.addSubview(self.view)
}

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    NSBundle.mainBundle().loadNibNamed("MediaPlayerView", owner: self, options: nil)
    self.addSubview(self.view)
}

But still got the error of the infinite loop.

I can't find a good solution to that and it's driving me crazy!! Somebody can help me please? Thanks!

like image 885
diegomen Avatar asked Jan 23 '15 08:01

diegomen


1 Answers

You're getting an infinite loop, because loadNibNamed(_,owner:,options:) call an init, so then try to load again the nib, and again an so on... Try this:

Swift 4

var contentView: UIView?

// MARK: Initializers

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

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

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    configureView()
}

override func awakeFromNib() {
    super.awakeFromNib()
    configureView()
}

// MARK: Config Functions

func configureView() {
    guard let view = defaultView() else { return }
    view.frame = bounds
    view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    addSubview(view)
    contentView = view

    updateView()
}

func defaultView() -> UIView? {
    // Create view from a nib with the same name
    let nibName = String(describing: type(of: self))
    let bundle = Bundle(for: type(of: self))
    let nib = UINib(nibName: nibName, bundle: bundle)

    return nib.instantiate(withOwner: self, options: nil).first as? UIView
}

What this code does, is load the view from the nib, an then adding it to a subview inside your view.

This will work also when adding your view on another xibs, add @IBDesignable and it will become available

like image 83
Fantini Avatar answered Dec 10 '22 21:12

Fantini