Layout Data

    let layoutData = NSData(contentsOfFile: Bundle.main.path(forResource: "ViewController", ofType: "json", inDirectory: "Layouts")!) as! Data

    self.layout = EverLayout(layoutData: layoutData, layoutIndexParser: LayoutIndexJSONParser())

A layout is initialized with a Data object. Generally layout data would be stored in a file loaded in from the Bundle, or the layout can be downloaded from a server.

The only requirement here is that your layout is correctly formatted for the parser. By default, EverLayout uses a JSON parser, but you can make your own parsers for any language by conforming to the different LayoutParser protocols.

Building Layout

    self.layout!.build(onView: self.view, viewEnvironment: self)

Building a layout requires a root view (see layout Index) and a View Environment is optional. If left nil, the root view will be used as the view environment.

Note - The instance of EverLayout should be strongly held. If the layout is deallocated, EverLayout Bridge won't be able to update it.

View Environment

A view environment is an instance of NSObject which contains the properties referenced in the layout file. For instance, in a View Controller, you would want the root view of your layout to be the controller's view, but the controller itself is the object containing the other views in your layout.

    class ViewController : UIViewController {
        private var layout : EverLayout(...)
        public let viewInLayout : UIView = UIView()

        override func viewDidLoad () {
            super.viewDidLoad()

            self.layout!.build(onView: self.view, viewEnvironment: self)
        }
    }
{
    "name":"ViewController",
    "root":{
        "views":{
            "viewInLayout":{
                ...
            }
        }
    }
}

In the above example, EverLayout will use the ViewController as the View Environment and find viewInLayout as a property. During the build process it will add this view to the root.

As EverLayout is looking for an NSObject as a View Environment, you can alternatively use an NSDictionary to directly pass the views into the layout. This is helpful when using loading layouts dynamically.

    let viewEnvironment : NSDictionary = [
        "viewInLayout": UIView()
    ]

    self.layout?.build(onView: self , viewEnvironment: viewEnvironment)

Note - NSDictionary can be used because it is a subclass of NSObject. The Swift Dictionary is not and will not work.

Note - Properties accessed from the View Environment must be public, otherwise you will likely crash and the world will come to an end.

View Index

A View Index is created by the layout when it builds. The View Index keeps track of all the views created in the layout and allows you to access them after the layout has successfully built.

    let wrapperView = self.layout?.viewIndex.view(forKey: "wrapperView")

Being able to access views from the View Index is helpful when the layout is creating new views (see Creating Views)

EverLayoutDelegate

Conform to EverLayoutDelegate and implement layout(_ layout:EverLayout , didBuildOnView: UIView) which is called when a layout successfully builds on a view.

Note - Make sure you set the delegate before building the layout.

Updating Constraints

During runtime you may wish to update the constant or multiplier on a constraint created in EverLayout. In layoutDidBuild you can access these constraints in various ways.

func layout(_ layout: EverLayout, didLoadOnView view: UIView) {
    if let myView = self.layout.viewIndex.viewModel(forKey: "myView") {
        if let heightConstraint = myView.getConstraints(forAttribute: .height).first {
            heightConstraint.constant = 120
        }
    }
}

You can target constraints belonging to a view model by both their attributes and their identifiers.