4

We use CGRect inside a frame specifying the width, height and the exact coordination of the rectangle (shape).

Do I need to specify constrains for the UI elements one by one as well? If yes, why do I need to? How about device rotation (portrait vs. landscape mode)? Do I need to define different positioning?

Rob
  • 415,655
  • 72
  • 787
  • 1,044
Danial Kosarifa
  • 1,044
  • 4
  • 18
  • 51

2 Answers2

4

If you are defining constraints you do not have to specify a CGRect frame for your design. In fact best way is to use NSLayoutConstraints. The reason is if you set the CGRect frame, when your device is rotating most of the time your CGRect can be wrong. At least hight and with. But if you use constraints when your device is rotating it will layout the subviews again automatically. Which means the views will rearrange according to the constraints.

When you set the CGRect frame what it does is, it changes the view's position and dimensions regardless of the constraints. Then if you try to call view.layoutIfNeeded() or change the orientation the views will be rearranged according to the constraints regardless the frame you set before.

LIH
  • 933
  • 2
  • 10
  • 25
0

tl;dr

Constraints are a rich and descriptive way of describing the size of views. The manually setting of a frame (and autoresizing mask) is a far older pattern and is not as flexible or as powerful. You certainly can set the frame and autoresizingMask, but we generally do not, and we tend to use constraints nowadays.


When defining the frame of a view, you have two alternatives:


For example, if you wanted to define an image view to be inset by 50pt horizontally, and 100pt vertically, you could do:

  • Use constraints:

     imageView.translatesAutoresizingMaskIntoConstraints = false
     NSLayoutConstraint.activate([
         imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50),
         imageView.trailingAnchor.constraint(equalTo: view.leadingAnchor, constant: -50),
         imageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
         imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -100)
     ])
    
  • Use frame/autoresizing mask:

     imageView.translatesAutoresizingMaskIntoConstraints = true
     imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
     imageView.frame = view.bounds.insetBy(dx: 50, dy: 100)
    

There are a few things to note:

  • It is not correct to conclude that setting frame manually means that you cannot respond to rotations (or other events that might change the size of the superview). Most, basic resizing logic can be handled quite gracefully with autoresizingMask. (Frankly, that is what we did before the auto-layout engine was introduced.)

  • Technically, both of these approaches are actually using constraints behind the scenes. The autoresizingMask/frame with translatesAutoresizingMaskIntoConstraints is just translating the frame and autoresizingMask into constraints for you.

  • The auto-layout engine and constraints are a far richer paradigm:

    • You can easily define constraints between views in different levels of the view hierarchy and/or between layout guides.
    • They support more complicated rules with separate multiplier and constant parameters, inequality operators, cascading priorities, etc.
    • They support dynamic layout for right-to-left languages.
    • They support different layouts for different size traits (e.g. rearranging items dynamically based upon the relative width or height of the view).

    All of these features largely eliminate the need to write code responding to the layout of subviews.

In short, using constraints has largely displaced the older technique of setting the frame and autoresizingMask.

Rob
  • 415,655
  • 72
  • 787
  • 1,044