Skip to content

Latest commit

 

History

History
106 lines (71 loc) · 4.84 KB

Layout.md

File metadata and controls

106 lines (71 loc) · 4.84 KB

Layout - Laying out and updating view hierarchies

The layout of a typical iOS application's UI consists of organizing views into hierarchies and letting auto layout position them by setting up constraints between views. Even though UIKit has great support for handling most of our layout needs, there is always room for some handy extensions and helpers to make working with layouts and view hierarchies even nicer.

Scroll views

Few layouts can rely on a static layout that will always fit within a screen. Often we have to work with devices of many different screen sizes. This means that we can seldom guarantee that all content will fit and hence we often place our content in scroll views.

Form adds several helpers to make it easier to work with scroll views. For example, to embed a view in a scroll view and to set up the required constraints:

scrollView.embedView(view, scrollAxis: .vertical)

If you want to embed multiple views where spacing is added between views to evenly fill up to the scroll views height, you can use:

bag += scrollView.embedWithSpacingBetween(views)

Form also provides helpers to pin a view to an edge of a scroll view and update the insets accordingly:

bag += scrollView.embedPinned(button, edge: .bottom, minHeight: 44)

View controller installation

As it is so common to set up your views in scroll views and also to set up your view controller to use this scroll view, Form provides the install helper:

bag += viewController.install(view)

This will create a scroll view and embed the view setup with constraints for vertical scrolling. Furthermore, it will by default setup the scroll view to adjust its insets to make room for a keyboard as well as scroll any first responder into view if it got covered by the keyboard. You can customize the behavior of install() by passing an explicit options parameter (InstallOptions).

You can also provide a configure closure for further setup once the created scroll view has been added to a window:

bag += viewController.install(view) { scrollView in
  // Not called until the scroll view has been added to a window.
}

Install can also be used for adding multiple views to a scroll view, and by default, space is added between views to evenly fill up to the scroll views height:

bag += viewController.install(topView, bottomView)

View embedding

Embedding views and setting up proper constraints for common scenarios can be repetitive and hence Form comes with some nice helpers to handle the most common cases. You can optionally provide customization such as edge insets or which edges to pin to:

parent.embedView(child, edgeInsets: ..., pinToEdge:..)

And for convenience you can use initializers as well:

let parent = UIView(embeddedView: child, edgeInsets: ..., pinToEdge:.. )

View hierarchies

Form comes with several helpers to work with view hierarchies such as getting a view's all ascendents or descendants and variants thereof. These are implemented as extensions on the ParentChildRelational protocol that UIView, as well as UIViewController and CALayer, conform to.

let controls = view.allDescendants(ofType: UIControl.self)

Working with constraints

Even though the many helpers provided by UIKit and Form will set up the constraints for you, you sometimes need to set some up by hand. Form comes with some convenience helpers to make it even more readable to work with layout anchors:

let topConstraint = self.topAnchor == view.topAnchor - margin 
activate(
  topConstraint,
  self.centerXAnchor == view.centerXAnchor,
  self.widthAnchor == view.widthAnchor*2,
  self.bottomAnchor == view.bottomAnchor + margin)

You can use ==, <= and >= to construct constraints between anchors and adjusting the constant with + and - and the multiplier with * and /. You can also use activate() for activating the constraints and deactivate() to deactivate them.

UINavigationItem

Navigation bars can hold several items to either the left or the right of a navigation bar. Form comes with some helpers to add items that also returns the added items for convenience:

let item = navigationItem.addItem(.init(system: .done), position: .right)
bag += item.onValue { ... }

SubviewOrderable

SubviewOrderable is a simple protocol for working with views such as UIStackView that has an array of ordered views. In Form, views such as SectionView and the helper RowAndProvider also conforms to this protocol. This allows us to add convenience helpers to SubviewOrderable such as different kinds of append and prepend helpers that will be available to all these conforming types. These are especially useful for building RowViews:

let row = RowView(title: "title", subtitle: "subtitle")
  .prepend(iconImage)
  .append("details")
  .append(.chevron)