How to describe layout in code

What do we have?


UI can be defined as a set of views that display data, respond to events, and at the same time are somehow located on the screen.


How do we place elements on the screen?


  • Qt suggests using containers that can arrange elements inside themselves in a certain way. By putting these containers into each other, you can get the necessary arrangement.
  • WPF / XAML offers similar containers.
  • Android offers similar containers + a constant system.
  • iOS offers Autolayout. It is necessary to describe a set of constraints (equations) that consistently and unambiguously describe the arrangement of elements. Having solved the system of equations with these restrictions, the engine will receive the coordinates and sizes of the elements.
  • Delphi has anchors: nailing edges to the container. Very similar to resizing masks in iOS.
  • As far as I understand, the web uses nesting containers, the behavior of which is described by styles.

What is the problem with this?


We need to use code for special cases


The described tools are sharpened for typical cases, often we cannot (or we can, but this is very inconvenient) describe the location of an element using these tools. You have to do it in code. The description logic of the layout is spread out in several places.
There must be a better way.


Layout - what is it really?


Layout is a function


What is layout? This is a description of the location of the elements. It can be expressed as a function.
At the input, the function receives the size of the container and an array of elements, at the output it gives the coordinates of these elements.
Theoretically, layout can be anything - that's how the designer will draw. Therefore, to describe such a function, we need a Turing-complete language. UI frameworks offer us anything but a Turing-complete language, hence the problems. It would be logical to take the language in which the rest of the program is written: for iOS - objc / swift, for android - java / kotlin, etc.


What does it mean?


We can easily describe layout in code


We can easily describe layout in code! It is enough to write one function. Often we will arrange elements relative to existing ones (to the right, lower, etc.). You can hide such calculations in functions with readable names. Under iOS, this is done in the libraries Facade (objc) , Neon (swift) . You can easily write your own in any language.


Example libraries


In iOS, if you want to define a custom layout for a view, you need to redefine the method layoutSubviews()(or viewDidLayoutSubviews()the controller) and set the frame in it to the child elements. This method is called when I resize the view, that is, turns, Split View, etc., will invoke the call to this method.


Here is an example from the official Neon page:


let isLandscape : Bool = UIDevice.currentDevice().orientation.isLandscape.boolValue
let bannerHeight : CGFloat = view.height() * 0.43
let avatarHeightMultipler : CGFloat = isLandscape ? 0.75 : 0.43
let avatarSize = bannerHeight * avatarHeightMultipler
searchBar.fillSuperview()
bannerImageView.anchorAndFillEdge(.Top, xPad: 0, yPad: 0, otherSize: bannerHeight)
bannerMaskView.fillSuperview()
avatarImageView.anchorInCorner(.BottomLeft, xPad: 15, yPad: 15, width: avatarSize, height: avatarSize)
nameLabel.alignAndFillWidth(align: .ToTheRightCentered, relativeTo: avatarImageView, padding: 15, height: 120)
cameraButton.anchorInCorner(.BottomRight, xPad: 10, yPad: 7, width: 28, height: 28)
buttonContainerView.alignAndFillWidth(align: .UnderCentered, relativeTo: bannerImageView, padding: 0, height: 62)
buttonContainerView.groupAndFill(group: .Horizontal, views: [postButton, updateInfoButton, activityLogButton, moreButton], padding: 10)
buttonContainerView2.alignAndFillWidth(align: .UnderCentered, relativeTo: buttonContainerView, padding: 0, height: 128)
buttonContainerView2.groupAndFill(group: .Horizontal, views: [aboutView, photosView, friendsView], padding: 10)

portrait
landscape


Not bad for 10 lines of code, right?


Pros


  • Computing frames is very fast. According to LayoutFrameworkBenchmark manual frame calculation is 10-15 times faster than Autolayout.
  • Layout code in one place - easier to maintain.
  • Easy debugging.
  • Full control, you can describe any layout.
  • Writing a UI in code naturally leads to decomposition and reuse of the view.
  • Writing a UI in code simplifies the use of shared resources (fonts, colors, etc.)

Cons


Often the UI is described declaratively in the form of markup (xml, xaml, xib), which then turns into code (Qt, Delphi, C # WinForms) or from which a ready-made graph of objects (xib, xaml) is created. At the same time, IDEs provide preview tools, which is very convenient.
Describing layout in the code, we abandon the preview tools.


Usually layout goes from top to bottom: we have the size of the screen, knowing this size, we layout the first layer of the view, having got their size we go deeper, etc. Sometimes you need to go the other way: stretch the container to fit the contents. Describing this is not always convenient.


What about RTL, Split View, iPhone X?


  • RTL - can be processed manually; there are also ready-made developments: for Neon, a PR hangs for using leading, trailing as in Autolayout.
  • Split View - you can catch the change in the trait collection and call different layout functions for each size class.
  • iPhone X - safeAreaGuide is available inside view, you can take into account the corresponding indentation.

Conclusion


In my opinion this is a good approach if you are already writing UI in code. The code in this case is approximately the same as when using Autolayout, but it works faster and more predictably.
The main disadvantage is that the visibility in the form of preview tools is lost.


Also popular now: