Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making a custom UIView subview that fills its superview

Tags:

ios

layout

swift

So I wrote my own custom view with its own initializer. However, when my main view loads my custom view gets depicted in a wrong way. It takes bounds as 600x600 rectangle, while the superview is 375x607. I did try to put auto constraint, seems not to work. I tried to do it programmatically in the subview initialization, but whenever I try to initialize it's bounds property to its superview bounds I get nil in superview.

override init(frame: CGRect) {
    super.init(frame: frame)
    self.setup()
}

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.setup()
}

func setup() {
    initPathLayer()
    initHandleView()
    initHandlePanGestureRecognizer()

    layoutPathLayer()
    layoutHandleViews()
}

I tried everything there is on the internet to make subview fill its superview, but I think that subview gets initialized before superview? Is that possible ? In the ViewController a have my custom view declared as an Outlet connection. I'm sure that the problem should be super easy and it's me who doesn't know the way Swift initializes the view.

Any ideas ?

Thank You.

like image 470
Olexiy Burov Avatar asked Apr 21 '15 05:04

Olexiy Burov


1 Answers

Firstly, a Views init method is not the best place to perform a layout. The view could be resized at a later point which is typically always the case if the view is loaded from a Xib or you are creating it in a View Controllers viewDidLoad function.

That being said you have several approaches:

1. Use Auto Layout

Interface Builder

This can be done either in Interface Builder or programmatically. In Interface Builder you simply use the 'Pin' option and select all the sides of the view

Pin Constraints

When this is done you should be able to see your constraints in the Size inspector looking as follows:

Size Inspector

Programmatically

Alternatively you can always add your constraints programmatically in your initializer:

override init(frame: CGRect) {
    let view = UIView(frame: .zero)
    view.translatesAutoresizingMaskIntoConstraints = false
    super.init(frame: frame)
    let viewsDict = ["view": view]
    addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view]-0-|", options: .allZeros, metrics: nil, views: viewsDict))
    addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view]-0-|", options: .allZeros, metrics: nil, views: viewsDict))
    addSubview(view)
}

convenience required init(coder aDecoder: NSCoder) {
    self.init(frame: .zero)
}

2. Manual Layout

Resizing Masks

For this you can either use resizing masks or you can control the frame in layoutSubviews. Resizing masks tell the system how the view should be sized relative to the superview:

override init(frame: CGRect) {
    let view = UIView(frame: CGRectZero)
    view.translatesAutoresizingMaskIntoConstraints = false
    super.init(frame: frame)
    view.frame = bounds
    view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    addSubview(view)
}

Layout Subviews

Lastly, you can override layoutSubviews and go from there:

override func layoutSubviews() {
    super.layoutSubviews()
    view.frame = bounds
}
like image 194
Daniel Galasko Avatar answered Dec 07 '22 18:12

Daniel Galasko